diff --git a/all/pom.xml b/all/pom.xml index a053ff60e80..090c12118dc 100644 --- a/all/pom.xml +++ b/all/pom.xml @@ -1088,38 +1088,6 @@ io.helidon.builder helidon-builder-codegen - - io.helidon.inject - helidon-inject-api - - - io.helidon.inject - helidon-inject-tools - - - io.helidon.inject - helidon-inject-processor - - - io.helidon.inject - helidon-inject-testing - - - io.helidon.inject - helidon-inject-runtime - - - io.helidon.inject.configdriven - helidon-inject-configdriven-api - - - io.helidon.inject.configdriven - helidon-inject-configdriven-runtime - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - io.helidon.service helidon-service-metadata @@ -1142,7 +1110,7 @@ io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-processor + helidon-integrations-oci-sdk-codegen io.helidon.integrations.oci.sdk diff --git a/bom/pom.xml b/bom/pom.xml index 1b2b21945fd..abdf40f0620 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -1441,50 +1441,6 @@ ${helidon.version} - - - io.helidon.inject - helidon-inject-api - ${helidon.version} - - - io.helidon.inject - helidon-inject-tools - ${helidon.version} - - - io.helidon.inject - helidon-inject-processor - ${helidon.version} - - - io.helidon.inject - helidon-inject-testing - ${helidon.version} - - - io.helidon.inject - helidon-inject-runtime - ${helidon.version} - - - - - io.helidon.inject.configdriven - helidon-inject-configdriven-api - ${helidon.version} - - - io.helidon.inject.configdriven - helidon-inject-configdriven-runtime - ${helidon.version} - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - ${helidon.version} - - io.helidon.service @@ -1517,7 +1473,7 @@ io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-processor + helidon-integrations-oci-sdk-codegen ${helidon.version} diff --git a/inject/README.md b/inject/README.md deleted file mode 100644 index 21262fe8829..00000000000 --- a/inject/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# helidon-inject - -Helidon inject is deprecated and will be replaced in a future version. -Please do not use any of the modules. - -This feature was marked as preview, and we have decided to do a major refactoring in this area, which will be -mostly backward incompatible. - -Sorry for this inconvenience. \ No newline at end of file diff --git a/inject/api/README.md b/inject/api/README.md deleted file mode 100644 index 9faed5242be..00000000000 --- a/inject/api/README.md +++ /dev/null @@ -1,112 +0,0 @@ -This module contains all the API and SPI types that are applicable to a Helidon Injection based application. - -The API can logically be broken up into two categories - declarative types and imperative/programmatic types. The declarative form is the most common approach for using Injection. - -The declarative API is small and based upon annotations. This is because most of the supporting annotation types actually come directly from both of the standard javax/jakarta inject and javax/jakarta annotation modules. These standard annotations are supplemented with these proprietary annotation types offered here from Injection: - -* [@Contract](src/main/java/io/helidon/inject/api/Contract.java) -* [@ExteralContracts](src/main/java/io/helidon/inject/api/ExternalContracts.java) -* [@RunLevel](src/main/java/io/helidon/inject/api/RunLevel.java) - -The programmatic API is typically used to manually lookup and activate services (those that are typically annotated with @jakarta.inject.Singleton for example) directly. The main entry points for programmatic access can start from one of these two types: - -* [InjectionServices](src/main/java/io/helidon/inject/api/InjectionServices.java) -* [Services](src/main/java/io/helidon/inject/api/Services.java) - -Note that this module only contains the common types for a Helidon Injection service provider. See the [runtime](../runtime) module for the default reference implementation for this API / SPI. - -## Declaring a Service - -### Singleton -In this example the service is declared to be one-per JVM. Also note that ApplicationScoped is effectively the same as Singleton scoped services in a (micro)services framework such as Helidon. - -```java -@jakarta.inject.Singleton -class MySingletonService implements ServiceContract { -} - -``` - -Also note that in the above example ServiceContract is typically the Contract or ExternalContract definition - which is a way to signify lookup capabilities within the Services registry. - -### Provider -Provider extends the Singleton to delegate dynamic behavior to service creation. In other frameworks this would typically be called a Factory, Producer, or PerLookup. - -```java -@jakarta.inject.Singleton -class MySingletonProvider implements jakarta.inject.Provider { - @Override - ServiceContract get() { - ... - } -} -``` - -Helidon Injection delegates the cardinality of to the provider implementation for which instance to return to the caller. However, note that the instances returned are not "owned" by the Injection framework - unless those instances are looked up out of the Services registry. - -### InjectionPointProvider -Here the standard jakarta.inject.Provider<> from above is extended to support contextual knowledge of "who is asking" to be injected with the service. In this way the provider implementation can provide the "right" instance based upon the caller's context. - -```java -@Singleton -@Named("*") -public class BladeProvider implements InjectionPointProvider { - @Override - public Optional first( - ContextualServiceQuery query) { - ServiceInfoCriteria criteria = query.serviceInfoCriteria(); - - AbstractBlade blade; - if (criteria.qualifiers().contains(all) || criteria.qualifiers().contains(coarse)) { - blade = new CoarseBlade(); - } else if (criteria.qualifiers().contains(fine)) { - blade = new FineBlade(); - } else { - assert (criteria.qualifiers().isEmpty()); - blade = new DullBlade(); - } - - return Optional.of(blade); - } -} -``` - -## Injectable Constructs -Any service can declare field, method, or constructor injection points. The only caveat is that these injectable elements must either be public or package private. Generally speaking, it is considered a best practice to (a) use only an injectable constructor, and (b) only inject Provider instances. Here is an example for best practice depicting all possible usages for injection types supported by Helidon Injection. - -```java -@Singleton -public class MainToolBox implements ToolBox { - - // generally not recommended - @Inject - Provider anyHammerProvider; - - // the best practice is to generally to use only constructor injection with Provider-wrapped types - @Inject - MainToolBox( - @Preferred Screwdriver screwdriver, // the qualifier restricts to the "preferred" screwdriver - List> allTools, // all tools in proper weighted/ranked order - @Named("big") Provider bigHammerProvider, // only the hammer provider qualified with name "big" - List> allHammers, // all hammers in proper weighted/ranked order - Optional maybeAChisel) // optionally a Chisel, activated - { - } - - // generally not recommended - @Inject - void setScrewdriver(Screwdriver screwdriver) { - } - - // called after construction by Injection's lifecycle startup management - @PostConstruct - void postConstruct() { - } - - // called before shutdown by Injection's lifecycle shutdown management - @PreDestroy - void preDestroy() { - } -} - -``` diff --git a/inject/api/pom.xml b/inject/api/pom.xml deleted file mode 100644 index 65380a55837..00000000000 --- a/inject/api/pom.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-api - Helidon Injection API / SPI - - - - io.helidon.common - helidon-common-types - - - io.helidon.common - helidon-common - - - io.helidon.common - helidon-common-config - - - io.helidon.logging - helidon-logging-common - - - jakarta.inject - jakarta.inject-api - compile - - - io.helidon.config - helidon-config-metadata - true - - - io.helidon.builder - helidon-builder-api - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationLog.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationLog.java deleted file mode 100644 index 929adce355d..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationLog.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -/** - * Tracks the transformations of {@link ServiceProvider}'s {@link ActivationStatus} in lifecycle activity (i.e., activation - * startup and deactivation shutdown). - * - * @see Activator - * @see DeActivator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ActivationLog { - - /** - * Expected to be called during service creation and activation to capture the activation log transcripts. - * - * @param entry the log entry to record - * @return the (perhaps decorated) activation log entry - */ - ActivationLogEntry record(ActivationLogEntry entry); - - /** - * Optionally provide a means to query the activation log, if query is possible. If query is not possible then an empty - * will be returned. - * - * @return the optional query API of log activation records - */ - default Optional toQuery() { - return Optional.empty(); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationLogEntryBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationLogEntryBlueprint.java deleted file mode 100644 index 5d5586d12b3..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationLogEntryBlueprint.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.time.Instant; -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Log entry for lifecycle related events (i.e., activation startup and deactivation shutdown). - * - * @see ActivationLog - * @see Activator - * @see DeActivator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint(decorator = ActivationLogEntryBlueprint.BuilderDecorator.class) -interface ActivationLogEntryBlueprint { - - /** - * The event. - * - * @return the event - */ - Event event(); - - /** - * Optionally, any special message being logged. - * - * @return the message - */ - Optional message(); - - /** - * Optionally, when this log entry pertains to a service provider activation. - * - * @return the activation result - */ - Optional activationResult(); - - /** - * Optionally, the managing service provider the event pertains to. - * - * @return the managing service provider - */ - Optional> serviceProvider(); - - /** - * Optionally, the injection point that the event pertains to. - * - * @return the injection point - */ - Optional injectionPoint(); - - /** - * The time this event was generated. - * - * @return the time of the event - */ - Instant time(); - - /** - * Any observed error during activation. - * - * @return any observed error - */ - Optional error(); - - /** - * The thread id that the event occurred on. - * - * @return the thread id - */ - @ConfiguredOption("0") - long threadId(); - - /** - * Ensures that the non-nullable fields are populated with default values. - */ - class BuilderDecorator implements Prototype.BuilderDecorator> { - - BuilderDecorator() { - } - - @Override - public void decorate(ActivationLogEntry.BuilderBase b) { - if (b.time().isEmpty()) { - b.time(Instant.now()); - } - - if (b.threadId() == 0) { - b.threadId(Thread.currentThread().threadId()); - } - - if (b.event().isEmpty()) { - b.event(Event.FINISHED); - } - } - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationLogQuery.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationLogQuery.java deleted file mode 100644 index 407838f8154..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationLogQuery.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.List; - -/** - * Provide a means to query the activation log. - * - * @see ActivationLog - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ActivationLogQuery extends Resettable { - - /** - * Clears the activation log. - * - * @param deep ignored - * @return true if the log was cleared, false if the log was previously empty - */ - @Override - boolean reset(boolean deep); - - /** - * The full transcript of all services phase transitions being managed. - * - * @return the activation log if log capture is enabled - */ - List fullActivationLog(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationPhaseReceiver.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationPhaseReceiver.java deleted file mode 100644 index 687b05d019b..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationPhaseReceiver.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * A receiver of events from the {@link Services} registry and providers held by the service registry. - *

- * Note that only {@link ServiceProvider}'s implement this contract that are also bound to the global - * {@link Services} registry are currently capable of receiving events. - * - * @see ServiceProviderBindable - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ActivationPhaseReceiver { - - /** - * Called when there is an event transition within the service registry. - * - * @param event the event - * @param phase the phase - */ - void onPhaseEvent(Event event, - Phase phase); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationRequestBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationRequestBlueprint.java deleted file mode 100644 index d0a5bc9607f..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationRequestBlueprint.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Request to activate a service. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface ActivationRequestBlueprint { - - /** - * Optionally, the injection point context information. - * - * @return injection point info - */ - Optional injectionPoint(); - - /** - * The phase to start activation. Typically, this should be left as the default (i.e., PENDING). - * - * @return phase to start - */ - Optional startingPhase(); - - /** - * Ultimate target phase for activation. - * - * @return phase to target - */ - @ConfiguredOption("ACTIVE") - Phase targetPhase(); - - /** - * Whether to throw an exception on failure to activate, or return an error activation result on activation. - * - * @return whether to throw on failure - */ - @ConfiguredOption("true") - boolean throwIfError(); -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationResultBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationResultBlueprint.java deleted file mode 100644 index b230f6aa9c4..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationResultBlueprint.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.Future; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Represents the result of a service activation or deactivation. - * - * @see Activator - * @see DeActivator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface ActivationResultBlueprint { - - /** - * The service provider undergoing activation or deactivation. - * - * @return the service provider generating the result - */ - ServiceProvider serviceProvider(); - - /** - * Optionally, given by the implementation provider to indicate the future completion when the provider's - * {@link ActivationStatus} is {@link ActivationStatus#WARNING_SUCCESS_BUT_NOT_READY}. - * - * @return the future result, assuming how activation can be async in nature - */ - Optional> finishedActivationResult(); - - /** - * The activation phase that was found at onset of the phase transition. - * - * @return the starting phase - */ - @ConfiguredOption("INIT") - Phase startingActivationPhase(); - - /** - * The activation phase that was requested at the onset of the phase transition. - * - * @return the target, desired, ultimate phase requested - */ - @ConfiguredOption("INIT") - Phase targetActivationPhase(); - - /** - * The activation phase we finished successfully on, or are otherwise currently in if not yet finished. - * - * @return the finishing phase - */ - Phase finishingActivationPhase(); - - /** - * How did the activation finish. - * Will only be populated if the lifecycle event has completed - see {@link #finishedActivationResult()}. - * - * @return the finishing status - */ - Optional finishingStatus(); - - /** - * The injection plan that was found or determined, key'ed by each element's {@link ServiceProvider#id()}. - * - * @return the resolved injection plan map - */ - Map injectionPlans(); - - /** - * The dependencies that were resolved or loaded, key'ed by each element's {@link ServiceProvider#id()}. - * - * @return the resolved dependency map - */ - Map resolvedDependencies(); - - /** - * Set to true if the injection plan in {@link #resolvedDependencies()} has been resolved and can be "trusted" as being - * complete and accurate. - * - * @return true if was resolved - */ - @ConfiguredOption("false") - boolean wasResolved(); - - /** - * Any throwable/exceptions that were observed during activation. - * - * @return any captured error - */ - Optional error(); - - /** - * Returns true if this result is finished. - * - * @return true if finished - */ - default boolean finished() { - Future f = finishedActivationResult().orElse(null); - return (f == null || f.isDone()); - } - - /** - * Returns true if this result was successful. - * - * @return true if successful - */ - default boolean success() { - return finishingStatus().orElse(null) != ActivationStatus.FAILURE; - } - - /** - * Returns true if this result was unsuccessful. - * - * @return true if unsuccessful - */ - default boolean failure() { - return !success(); - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationStatus.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationStatus.java deleted file mode 100644 index 255d695ce87..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationStatus.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * The activation status. This status applies to the {@link ActivationLogEntry} record. - * - * @see Activator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public enum ActivationStatus { - - /** - * The service has been activated and is fully ready to receive requests. - */ - SUCCESS, - - /** - * The service has been activated but is still being started asynchronously, and is not fully ready yet to receive requests. - * Important note: This is NOT health related - Health is orthogonal to service bindings/activation and readiness. - */ - WARNING_SUCCESS_BUT_NOT_READY, - - /** - * A general warning during lifecycle. - */ - WARNING_GENERAL, - - /** - * Failed to activate to the given phase. - */ - FAILURE - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Activator.java b/inject/api/src/main/java/io/helidon/inject/api/Activator.java deleted file mode 100644 index 79888c80179..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Activator.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Activators are responsible for lifecycle creation and lazy activation of service providers. They are responsible for taking the - * {@link ServiceProvider}'s manage service instance from {@link Phase#PENDING} - * through {@link Phase#POST_CONSTRUCTING} (i.e., including any - * {@link PostConstructMethod} invocations, etc.), and finally into the - * {@link Phase#ACTIVE} phase. - *

- * Assumption: - *

    - *
  1. Each {@link ServiceProvider} managing its backing service will have an activator strategy conforming to the DI - * specification.
  2. - *
  3. Each services activation is expected to be non-blocking, but may in fact require deferred blocking activities to become - * fully ready for runtime operation.
  4. - *
- * Activation includes: - *
    - *
  1. Management of the service's {@link Phase}.
  2. - *
  3. Control over creation (i.e., invoke the constructor non-reflectively).
  4. - *
  5. Control over gathering the service requisite dependencies (ctor, field, setters) and optional activation of those.
  6. - *
  7. Invocation of any {@link PostConstructMethod}.
  8. - *
  9. Responsible to logging to the {@link ActivationLog} - see {@link InjectionServices#activationLog()}.
  10. - *
- * - * @see DeActivator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface Activator { - - /** - * Activate a managed service/provider. - * - * @param activationRequest activation request - * @return the result of the activation - */ - ActivationResult activate(ActivationRequest activationRequest); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Application.java b/inject/api/src/main/java/io/helidon/inject/api/Application.java deleted file mode 100644 index 1c10a2c1425..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Application.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * An Application instance, if available at runtime, will be expected to provide a blueprint for all service provider's injection - * points. - *

- * Implementations of this contract are normally code generated, although then can be programmatically written by the developer - * for special cases. - *

- * Note: instances of this type are not eligible for injection. - * - * @see ModuleComponent - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface Application extends OptionallyNamed { - - /** - * Called by the provider implementation at bootstrapping time to bind all injection plans to each and every service provider. - * - * @param binder the binder used to register the service provider injection plans - */ - void configure(ServiceInjectionPlanBinder binder); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/BootstrapBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/BootstrapBlueprint.java deleted file mode 100644 index 56ffa395a5c..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/BootstrapBlueprint.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.config.Config; - -/** - * This is the bootstrap needed to provide to {@code Services} initialization. - * - * @see io.helidon.inject.spi.InjectionServicesProvider - * @see io.helidon.inject.api.InjectionServices#globalBootstrap() - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface BootstrapBlueprint { - - /** - * Provides the base primordial bootstrap configuration to the {@link io.helidon.inject.spi.InjectionServicesProvider}. - * The provider will then bootstrap {@link InjectionServices} using this bootstrap instance. - * then default values will be used accordingly. - * - * @return the bootstrap helidon configuration - */ - Optional config(); - - /** - * In certain conditions Injection services should be initialized but not started (i.e., avoiding calls to {@code PostConstruct} - * etc.). This can be used in special cases where the normal Injection startup should limit lifecycle up to a given phase. Normally - * one should not use this feature - it is mainly used in Injection tooling (e.g., the injection maven-plugin). - * - * @return the phase to stop at during lifecycle - */ - Optional limitRuntimePhase(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/CallingContextBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/CallingContextBlueprint.java deleted file mode 100644 index c0233dd7aa5..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/CallingContextBlueprint.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import io.helidon.builder.api.Prototype; - -/** - * For internal use only to Helidon. Applicable when {@link InjectionServices#TAG_DEBUG} is enabled. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint(decorator = CallingContextBlueprint.BuilderDecorator.class) -interface CallingContextBlueprint { - /** - * Only populated when {@link InjectionServices#TAG_DEBUG} is set. - * - * @return the stack trace for who initialized - */ - Optional stackTrace(); - - /** - * Only populated when {@code module} is set. - * - * @return the module name - */ - Optional moduleName(); - - /** - * The thread that created the calling context. - * - * @return thread creating the calling context - */ - String threadName(); - - /** - * Returns a stack trace as a list of strings. - * - * @return the list of strings for the stack trace, or empty list if not available - */ - default List stackTraceAsList() { - return stackTrace().map(stackTrace -> { - List result = new ArrayList<>(); - for (StackTraceElement e : stackTrace) { - result.add(e.toString()); - } - return result; - }) - .orElseGet(List::of); - } - - class BuilderDecorator implements Prototype.BuilderDecorator> { - @Override - public void decorate(CallingContext.BuilderBase target) { - if (target.threadName().isEmpty()) { - target.threadName(Thread.currentThread().getName()); - } - } - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/CallingContextFactory.java b/inject/api/src/main/java/io/helidon/inject/api/CallingContextFactory.java deleted file mode 100644 index f6d9fa543ed..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/CallingContextFactory.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Objects; -import java.util.Optional; - -/** - * Factory for creating {@link CallingContext} and builders for the calling context. - * After a calling context builder is created, it should be amended with as much contextual information as possible, and then - * optionally set globally using {@link #globalCallingContext(CallingContext, boolean)}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class CallingContextFactory { - private static volatile CallingContext defaultCallingContext; - - private CallingContextFactory() { - } - - /** - * Sets the default global calling context. - * - * @param callingContext the default global context - * @param throwIfAlreadySet should an exception be thrown if the global calling context was already set - * @throws java.lang.IllegalStateException if context was already set and the throwIfAlreadySet is active - */ - public static void globalCallingContext(CallingContext callingContext, - boolean throwIfAlreadySet) { - Objects.requireNonNull(callingContext); - - CallingContext global = defaultCallingContext; - if (global != null && throwIfAlreadySet) { - CallingContext currentCallingContext = CallingContextFactory.create(true).orElseThrow(); - throw new IllegalStateException("Expected to be the owner of the calling context. This context is: " - + currentCallingContext + "\n Context previously set was: " + global); - } - - CallingContextFactory.defaultCallingContext = callingContext; - } - - /** - * Creates a new calling context instance. Normally this method will return a context optionally only when debug is - * enabled. This behavior can be overridden by passing the {@code force=true} flag. - * - * @param force forces the creation of the calling context even when debug is disabled - * @return a new calling context if there is an indication that debug mode is enabled, or if the force flag is set - * @see InjectionServicesConfig#debug() - */ - public static Optional create(boolean force) { - Optional optBuilder = createBuilder(force); - return optBuilder.map(CallingContext.Builder::build); - - } - - /** - * Creates a new calling context builder instance. Normally this method will return a context builder optionally only when - * debug is enabled. This behavior can be overridden by passing the {@code force=true} flag. - * - * @param force forces the creation of the calling context even when debug is disabled - * @return a new calling context builder if there is an indication that debug mode is enabled, or if the force flag is set - * @see InjectionServicesConfig#debug() - */ - public static Optional createBuilder(boolean force) { - if (force || InjectionServices.injectionServices() - .map(InjectionServices::config) - .map(InjectionServicesConfig::shouldDebug) - .orElse(false)) { - - return Optional.of(CallingContext.builder() - .stackTrace(new RuntimeException().getStackTrace())); - } - return Optional.empty(); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ClassNamed.java b/inject/api/src/main/java/io/helidon/inject/api/ClassNamed.java deleted file mode 100644 index 9a745aafda5..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ClassNamed.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import jakarta.inject.Named; -import jakarta.inject.Qualifier; - -/** - * This annotation is effectively the same as {@link jakarta.inject.Named} where the {@link Named#value()} is a {@link Class} - * name instead of a {@link String}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Qualifier -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface ClassNamed { - - /** - * The class used will function as the name. - * - * @return the class - */ - Class value(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/CommonQualifiers.java b/inject/api/src/main/java/io/helidon/inject/api/CommonQualifiers.java deleted file mode 100644 index aae90540075..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/CommonQualifiers.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import io.helidon.common.types.TypeName; - -import jakarta.inject.Named; - -/** - * Commonly used {@link Qualifier} types. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public final class CommonQualifiers { - - /** - * Represents a {@link jakarta.inject.Named} type name with no value. - */ - public static final TypeName NAMED = TypeName.create(Named.class); - - /** - * Represents a wildcard (i.e., matches anything). - */ - public static final String WILDCARD = "*"; - - /** - * Represents a wildcard {@link #NAMED} qualifier. - */ - public static final Qualifier WILDCARD_NAMED = Qualifier.createNamed(WILDCARD); - - private CommonQualifiers() { - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ContextualServiceQueryBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ContextualServiceQueryBlueprint.java deleted file mode 100644 index 14ce4c494b7..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ContextualServiceQueryBlueprint.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Objects; -import java.util.Optional; - -import io.helidon.builder.api.Prototype; - -/** - * Combines the {@link ServiceInfo} criteria along with the {@link InjectionPointInfo} context - * that the query applies to. - * - * @see InjectionPointProvider - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -@Prototype.CustomMethods(ContextualServiceQueryBlueprint.CustomMethods.class) -interface ContextualServiceQueryBlueprint { - - /** - * The criteria to use for the lookup into {@link Services}. - * - * @return the service info criteria - */ - ServiceInfoCriteria serviceInfoCriteria(); - - /** - * Optionally, the injection point context this search applies to. - * - * @return the optional injection point context info - */ - Optional injectionPointInfo(); - - /** - * Set to true if there is an expectation that there is at least one match result from the search. - * - * @return true if it is expected there is at least a single match result - */ - boolean expected(); - - final class CustomMethods { - private CustomMethods() { - } - - /** - * Creates a contextual service query given the injection point info. - * - * @param ipInfo the injection point info - * @param expected true if the query is expected to at least have a single match - * @return the query - */ - @Prototype.FactoryMethod - static ContextualServiceQuery create(InjectionPointInfo ipInfo, - boolean expected) { - Objects.requireNonNull(ipInfo); - return ContextualServiceQuery.builder() - .expected(expected) - .injectionPointInfo(ipInfo) - .serviceInfoCriteria(ipInfo.dependencyToServiceInfo()) - .build(); - } - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Contract.java b/inject/api/src/main/java/io/helidon/inject/api/Contract.java deleted file mode 100644 index 6410802dd9c..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Contract.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * The {@code Contract} annotation is used to relay significance to the type that it annotates. While remaining optional in its - * use, it is typically placed on an interface definition to signify that the given type can be used for lookup in the - * {@link Services} registry, and be eligible for injection via standard {@code @Inject}. - * While normally placed on interface types, it can also be placed on abstract and concrete class as well. The main point is that - * a {@code Contract} is the focal point for service lookup and injection. - *

- * If the developer does not have access to the source to place this annotation on the interface definition directly then consider - * using {@link ExternalContracts} instead - this annotation can be placed on the implementation class implementing the given - * {@code Contract} interface(s). - * - * @see ServiceInfo#contractsImplemented() - * @see ServiceInfo#externalContractsImplemented() - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Documented -@Retention(RetentionPolicy.CLASS) -@Target(java.lang.annotation.ElementType.TYPE) -public @interface Contract { - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/DeActivationRequestBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/DeActivationRequestBlueprint.java deleted file mode 100644 index 60ed27266ba..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/DeActivationRequestBlueprint.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Request to deactivate a {@link ServiceProvider}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface DeActivationRequestBlueprint { - /** - * Whether to throw an exception on failure, or return it as part of the result. - * - * @return throw on failure - */ - @ConfiguredOption("true") - boolean throwIfError(); -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/DeActivator.java b/inject/api/src/main/java/io/helidon/inject/api/DeActivator.java deleted file mode 100644 index 93e22d5cb1d..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/DeActivator.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * DeActivators are responsible for lifecycle, transitioning a {@link ServiceProvider} through its - * {@link Phase}'s, notably including any - * {@link jakarta.annotation.PreDestroy} method invocations, and finally into the terminal - * {@link Phase#DESTROYED} phase. These phase transitions are the inverse of {@link Activator}. - * - * @see Activator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface DeActivator { - - /** - * Deactivate a managed service. This will trigger any {@link jakarta.annotation.PreDestroy} method on the - * underlying service type instance. - * - * @param request deactivation request - * @return the result - */ - ActivationResult deactivate(DeActivationRequest request); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/DependenciesInfoBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/DependenciesInfoBlueprint.java deleted file mode 100644 index 055bdb29e1a..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/DependenciesInfoBlueprint.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * Represents a per {@link ServiceInfo} mapping of {@link DependencyInfo}'s. These are typically assigned to a - * {@link ServiceProvider} via compile-time code generation within the Injection framework. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface DependenciesInfoBlueprint { - /** - * Represents the set of dependencies for each {@link ServiceInfo}. - * - * @return map from the service info to its dependencies - */ - @Option.Singular("serviceInfoDependency") - Map> serviceInfoDependencies(); - - /** - * Optionally, the service type name aggregating {@link #allDependencies()}. - * - * @return the optional service type name for which these dependencies belong - */ - Optional fromServiceTypeName(); - - /** - * Represents a flattened set of all dependencies. - * - * @return the flattened set of all dependencies - */ - default Set allDependencies() { - Set all = new TreeSet<>(DependencyInfoComparator.instance()); - serviceInfoDependencies().values() - .forEach(all::addAll); - return all; - } - - /** - * Represents the list of all dependencies for a given injection point element name ordered by the element position. - * - * @param elemName the element name of the injection point - * @return the list of all dependencies got a given element name of a given injection point - */ - default List allDependenciesFor(String elemName) { - Objects.requireNonNull(elemName); - return allDependencies().stream() - .flatMap(dep -> dep.injectionPointDependencies().stream() - .filter(ipi -> elemName.equals(ipi.elementName())) - .map(ipi -> DependencyInfo.builder(dep) - .injectionPointDependencies(Set.of(ipi)) - .build())) - .sorted(DependencyInfoComparator.instance()) - .collect(Collectors.toList()); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/DependencyInfoBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/DependencyInfoBlueprint.java deleted file mode 100644 index 8ffa8ff0cbe..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/DependencyInfoBlueprint.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Aggregates the set of {@link InjectionPointInfo}'s that are dependent upon a specific and common - * {@link ServiceInfo} definition. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface DependencyInfoBlueprint { - /** - * Name of the dependency location, such as a field name, or argument name. - * - * @return name of the element of this dependency - */ - String elementName(); - - /** - * The service info describing what the injection point dependencies are dependent upon. - * - * @return the service info dependency - */ - @ConfiguredOption(required = true) - ServiceInfoCriteria dependencyTo(); - - /** - * The set of injection points that depends upon {@link #dependencyTo()}. - * - * @return the set of dependencies - */ - @Option.Singular("injectionPointDependency") - Set injectionPointDependencies(); - - /** - * The {@link ServiceProvider} that this dependency is optional resolved and bound to. All dependencies - * from {@link #injectionPointDependencies()} will be bound to this resolution. - * - * @return the optional resolved and bounded service provider - */ - Optional> resolvedTo(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/DependencyInfoComparator.java b/inject/api/src/main/java/io/helidon/inject/api/DependencyInfoComparator.java deleted file mode 100644 index afb7c666646..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/DependencyInfoComparator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.io.Serializable; -import java.util.Comparator; - -/** - * Comparator appropriate for {@link DependencyInfo}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class DependencyInfoComparator implements java.util.Comparator, Serializable { - private static final Comparator INSTANCE = new DependencyInfoComparator(); - - private DependencyInfoComparator() { - } - - /** - * Dependency info comparator. - * - * @return instance of the comparator - */ - public static Comparator instance() { - return INSTANCE; - } - - @Override - public int compare(DependencyInfo o1, - DependencyInfo o2) { - InjectionPointInfo ipi1 = o1.injectionPointDependencies().iterator().next(); - InjectionPointInfo ipi2 = o2.injectionPointDependencies().iterator().next(); - - java.util.Comparator idComp = java.util.Comparator.comparing(InjectionPointInfo::baseIdentity); - java.util.Comparator posComp = - java.util.Comparator.comparing(DependencyInfoComparator::elementOffsetOf); - - return idComp.thenComparing(posComp).compare(ipi1, ipi2); - } - - private static int elementOffsetOf(InjectionPointInfo ipi) { - return ipi.elementOffset().orElse(0); - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ElementInfoBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ElementInfoBlueprint.java deleted file mode 100644 index c9fb39a489b..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ElementInfoBlueprint.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Abstractly describes method or field elements of a managed service type (i.e., fields, constructors, injectable methods, etc.). - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface ElementInfoBlueprint { - - /** - * The name assigned to constructors. - */ - String CONSTRUCTOR = ""; - - /** - * The injection point/receiver kind. - * - * @return the kind - */ - ElementKind elementKind(); - - /** - * The access modifier on the injection point/receiver. - * - * @return the access - */ - AccessModifier access(); - - /** - * The element type name (e.g., method type or field type). - * - * @return the target receiver type name - */ - TypeName elementTypeName(); - - /** - * The element name (e.g., method name or field name). - * - * @return the target receiver name - */ - String elementName(); - - /** - * If the element is a method or constructor then this is the ordinal argument position of that argument. - * - * @return the offset argument, 0 based, or empty if field type - */ - Optional elementOffset(); - - /** - * If the element is a method or constructor then this is the total argument count for that method. - * - * @return total argument count - */ - Optional elementArgs(); - - /** - * True if the injection point is static. - * - * @return true if static receiver - */ - @ConfiguredOption("false") - boolean staticDeclaration(); - - /** - * The enclosing class name for the element. - * - * @return service type name - */ - TypeName serviceTypeName(); - - /** - * The annotations on this element. - * - * @return the annotations on this element - */ - @Option.Singular - Set annotations(); - - /** - * The qualifier type annotations on this element. - * - * @return the qualifier type annotations on this element - */ - @Option.Singular - Set qualifiers(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ElementKind.java b/inject/api/src/main/java/io/helidon/inject/api/ElementKind.java deleted file mode 100644 index 04c42d6f1c6..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ElementKind.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * The kind of injection target. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public enum ElementKind { - /** - * The injectable constructor. Note that there can be at most 1 injectable constructor. - */ - CONSTRUCTOR, - - /** - * A field. - */ - FIELD, - - /** - * A method. - */ - METHOD -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ExternalContracts.java b/inject/api/src/main/java/io/helidon/inject/api/ExternalContracts.java deleted file mode 100644 index af571e43772..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ExternalContracts.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Placed on the implementation of a service as an alternative to using a {@link Contract}. - *

- * Use this annotation when it is impossible to place an annotation on the interface itself - for instance of the interface comes - * from a 3rd party library provider. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Documented -@Retention(RetentionPolicy.CLASS) -@Target(java.lang.annotation.ElementType.TYPE) -public @interface ExternalContracts { - - /** - * The advertised contract type(s) for the service class implementation. - * - * @return the external contract(s) - */ - Class[] value(); - - /** - * The optional set of module names where this contract is expected to reside. - * - * @return the optional module names - */ - String[] moduleNames() default {}; - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Helidon.java b/inject/api/src/main/java/io/helidon/inject/api/Helidon.java deleted file mode 100644 index d8de355e6a9..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Helidon.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import io.helidon.common.config.Config; -import io.helidon.common.config.GlobalConfig; -import io.helidon.logging.common.LogConfig; - -/** - * Entry point to service registry based Helidon applications. - * - * @see #start() - * @see #serviceRegistry() - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class Helidon { - private static final System.Logger LOGGER = System.getLogger(Helidon.class.getName()); - private static final ReentrantReadWriteLock REENTRANT_READ_WRITE_LOCK = new ReentrantReadWriteLock(); - private static final ReentrantReadWriteLock.ReadLock READ_LOCK = REENTRANT_READ_WRITE_LOCK.readLock(); - private static final ReentrantReadWriteLock.WriteLock WRITE_LOCK = REENTRANT_READ_WRITE_LOCK.writeLock(); - private static final AtomicBoolean BASIC_INIT_DONE = new AtomicBoolean(); - private static final AtomicBoolean REGISTRY_INITIALIZED = new AtomicBoolean(); - private static final AtomicBoolean STARTED = new AtomicBoolean(); - - static { - LogConfig.initClass(); - ResettableHandler.registerReset(); - } - - private Helidon() { - } - - /** - * Initialize Helidon Injection service registry. In case the intent is to also start services, such as WebServer, - * see {@link #start()}. - * - * @return service registry - */ - public static Services serviceRegistry() { - if (REGISTRY_INITIALIZED.compareAndSet(false, true)) { - basicInit(); - registryInit(false); - } - try { - READ_LOCK.lock(); - return InjectionServices.realizedServices(); - } finally { - READ_LOCK.unlock(); - } - } - - /** - * Initialize Helidon Injection service registry, and start all startable services. - */ - public static void start() { - if (STARTED.compareAndSet(false, true)) { - basicInit(); - registryInit(true); - } else { - LOGGER.log(System.Logger.Level.WARNING, "Helidon.start() has already been called."); - } - } - - private static boolean reset(boolean deep) { - // for testing purposes - BASIC_INIT_DONE.set(false); - REGISTRY_INITIALIZED.set(false); - STARTED.set(false); - - return true; - } - - private static void registryInit(boolean bootServices) { - try { - WRITE_LOCK.lock(); - - boolean explicitConfig = GlobalConfig.configured(); - Config bootstrapConfig = GlobalConfig.config(); - - Bootstrap bootstrap = Bootstrap.builder() - .config(bootstrapConfig) - .build(); - - InjectionServices.globalBootstrap(bootstrap); - Services services = InjectionServices.realizedServices(); - - if (!explicitConfig) { - GlobalConfig.config(() -> services.lookup(Config.class).get(), true); - } - - if (bootServices) { - services.lookupAll(Startable.class) - .stream() - .map(ServiceProvider::get) - .forEach(Startable::startService); - } - } finally { - WRITE_LOCK.unlock(); - } - } - - private static void basicInit() { - if (BASIC_INIT_DONE.compareAndSet(false, true)) { - LogConfig.configureRuntime(); - } - } - - private static final class ResettableHandler extends InjectionServicesHolder { - @Deprecated - private ResettableHandler() { - } - - private static void registerReset() { - InjectionServicesHolder.addResettable(Helidon::reset); - } - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectionException.java b/inject/api/src/main/java/io/helidon/inject/api/InjectionException.java deleted file mode 100644 index 7002ce91c59..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectionException.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * A general exception indicating that something failed related to Injection. - * - * @see InjectionServiceProviderException - * @see ServiceProviderInjectionException - * @see InvocationException - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class InjectionException extends RuntimeException { - - /** - * A general purpose exception from the Injection Framework. - * - * @param msg the message - */ - public InjectionException(String msg) { - super(msg); - } - - /** - * A general purpose exception from the Injection framework. - * - * @param msg the message - * @param cause the root cause - */ - public InjectionException(String msg, - Throwable cause) { - super(msg, cause); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectionPointInfoBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/InjectionPointInfoBlueprint.java deleted file mode 100644 index 36fcdd48588..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectionPointInfoBlueprint.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Describes a receiver for injection - identifies who/what is requesting an injection that needs to be satisfied. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface InjectionPointInfoBlueprint extends ElementInfo, ElementInfoBlueprint { - /** - * Name of the field or argument we are injecting into. - * Best effort, if cannot be found, an indexed approach may be used (such as {@code arg0}). - * - * @return name of the injection point field or argument - */ - String ipName(); - - /** - * Type of the field or argument we are injecting into. - * - * @return type of the field or argument, including generic type declarations - */ - TypeName ipType(); - - /** - * The identity (aka id) for this injection point. The id should be unique for the service type it is contained within. - *

- * This method will return the {@link #baseIdentity()} when {@link #elementOffset()} is null. If not null - * then the elemOffset is part of the returned identity. - * - * @return the unique identity - */ - String id(); - - /** - * The base identifying name for this injection point. If the element represents a function, then the function arguments - * are encoded in its base identity. - * - * @return the base identity of the element - */ - String baseIdentity(); - - /** - * True if the injection point is of type {@link java.util.List}. - * - * @return true if list based receiver - */ - @ConfiguredOption("false") - boolean listWrapped(); - - /** - * True if the injection point is of type {@link java.util.Optional}. - * - * @return true if optional based receiver - */ - @ConfiguredOption("false") - boolean optionalWrapped(); - - /** - * True if the injection point is of type Provider (or Supplier). - * - * @return true if provider based receiver - */ - @ConfiguredOption("false") - boolean providerWrapped(); - - /** - * The service info criteria/dependency this is dependent upon. - * - * @return the service info criteria we are dependent upon - */ - ServiceInfoCriteria dependencyToServiceInfo(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectionPointProvider.java b/inject/api/src/main/java/io/helidon/inject/api/InjectionPointProvider.java deleted file mode 100644 index 701c4634823..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectionPointProvider.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.List; -import java.util.Optional; - -import jakarta.inject.Provider; - -/** - * Provides ability to contextualize the injected service by the target receiver of the injection point dynamically - * at runtime. This API will provide service instances of type {@code T}. These services may be singleton, or created based upon - * scoping cardinality that is defined by the provider implementation of the given type. This is why the javadoc reads "get (or - * create)". - *

- * The ordering of services, and the preferred service itself, is determined by the same as documented for - * {@link Services}. - * - * @param the type that the provider produces - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface InjectionPointProvider extends Provider { - - /** - * Get (or create) an instance of this service type using default/empty criteria and context. - * - * @return the best service provider matching the criteria - * @throws InjectionException if resolution fails to resolve a match - */ - @Override - default T get() { - return first(InjectionServices.SERVICE_QUERY_REQUIRED) - .orElseThrow(this::couldNotFindMatch); - } - - /** - * Get (or create) an instance of this service type for the given injection point context. This is logically the same - * as using the first element of the result from calling {@link #list(ContextualServiceQuery)}. - * - * @param query the service query - * @return the best service provider matching the criteria - * @throws InjectionException if expected=true and resolution fails to resolve a match - */ - Optional first(ContextualServiceQuery query); - - /** - * Get (or create) a list of instances matching the criteria for the given injection point context. - * - * @param query the service query - * @return the resolved services matching criteria for the injection point in order of weight, or null if the context is not - * supported - */ - default List list(ContextualServiceQuery query) { - return first(query).map(List::of).orElseGet(List::of); - } - - private InjectionException couldNotFindMatch() { - if (this instanceof ServiceProvider) { - return new InjectionServiceProviderException("Expected to find a match", (ServiceProvider) this); - } - return new InjectionException("Expected to find a match for " + this); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectionServiceProviderException.java b/inject/api/src/main/java/io/helidon/inject/api/InjectionServiceProviderException.java deleted file mode 100644 index 22662e3df3c..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectionServiceProviderException.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Objects; -import java.util.Optional; - -/** - * An exception relative to a {@link ServiceProvider}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class InjectionServiceProviderException extends InjectionException { - - /** - * The service provider this exception pertains. - */ - private final ServiceProvider serviceProvider; - - /** - * A general purpose exception from the Injection framework. - * - * @param msg the message - */ - public InjectionServiceProviderException(String msg) { - super(msg); - this.serviceProvider = null; - } - - /** - * A general purpose exception from the Injection framework. - * - * @param msg the message - * @param cause the root cause - */ - public InjectionServiceProviderException(String msg, - Throwable cause) { - super(msg, cause); - - if (cause instanceof InjectionServiceProviderException exc) { - this.serviceProvider = exc.serviceProvider().orElse(null); - } else { - this.serviceProvider = null; - } - } - - /** - * A general purpose exception from the Injection framework. - * - * @param msg the message - * @param serviceProvider the service provider - */ - public InjectionServiceProviderException(String msg, - ServiceProvider serviceProvider) { - super(msg); - Objects.requireNonNull(serviceProvider); - this.serviceProvider = serviceProvider; - } - - /** - * A general purpose exception from the Injection framework. - * - * @param msg the message - * @param cause the root cause - * @param serviceProvider the service provider - */ - public InjectionServiceProviderException(String msg, - Throwable cause, - ServiceProvider serviceProvider) { - super(msg, cause); - Objects.requireNonNull(serviceProvider); - this.serviceProvider = serviceProvider; - } - - /** - * The service provider that this exception pertains to, or empty if not related to any particular provider. - * - * @return the optional / contextual service provider - */ - public Optional> serviceProvider() { - return Optional.ofNullable(serviceProvider); - } - - @Override - public String getMessage() { - return super.getMessage() - + (serviceProvider == null ? "" : (": service provider: " + serviceProvider)); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectionServices.java b/inject/api/src/main/java/io/helidon/inject/api/InjectionServices.java deleted file mode 100644 index 959ef009940..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectionServices.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.types.TypeName; - -/** - * Abstract factory for all services provided by a single Helidon Injection provider implementation. - * An implementation of this interface must minimally supply a "services registry" - see {@link #services()}. - *

- * The global singleton instance is accessed via {@link #injectionServices()}. Note that optionally one can provide a - * primordial bootstrap configuration to the {@code Injection} services provider. One must establish any bootstrap instance - * prior to the first call to {@link #injectionServices()} as it will use a default configuration if not explicitly set. Once - * the bootstrap has been set it cannot be changed for the lifespan of the JVM. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface InjectionServices { - /** - * Tag for putting Injection tooling, processing, and runtime into debug mode. - * @see InjectionServices#config() - * @see InjectionServicesConfig#shouldDebug() - */ - String TAG_DEBUG = "inject.debug"; - - - /** - * Empty criteria will match anything and everything. - */ - ServiceInfoCriteria EMPTY_CRITERIA = ServiceInfoCriteria.builder().build(); - - /** - * Denotes a match to any (default) service, but required to be matched to at least one. - */ - ContextualServiceQuery SERVICE_QUERY_REQUIRED = ContextualServiceQuery.builder() - .serviceInfoCriteria(EMPTY_CRITERIA) - .expected(true) - .build(); - - /** - * Whether debug is enabled. - * - * @return whether to debug - */ - static boolean isDebugEnabled() { - return injectionServices() - .map(InjectionServices::config) - .map(InjectionServicesConfig::shouldDebug) - .orElseGet(() -> Boolean.getBoolean(InjectionServices.TAG_DEBUG)); - } - - /** - * Returns the {@link Bootstrap} configuration instance that was used to initialize this instance. - * - * @return the bootstrap configuration instance - */ - Bootstrap bootstrap(); - - /** - * Retrieves any primordial bootstrap configuration that previously set. - * - * @return the bootstrap primordial configuration already assigned - * @see #globalBootstrap(Bootstrap) - */ - static Optional globalBootstrap() { - return InjectionServicesHolder.bootstrap(false); - } - - /** - * First attempts to locate and return the {@link #globalBootstrap()} and if not found will create a new bootstrap instance. - * - * @return a bootstrap - */ - static Bootstrap realizedGlobalBootStrap() { - Optional bootstrap = globalBootstrap(); - return bootstrap.orElseGet(() -> InjectionServicesHolder.bootstrap(true).orElseThrow()); - } - - /** - * Sets the primordial bootstrap configuration that will supply {@link #injectionServices()} during global - * singleton initialization. - * - * @param bootstrap the primordial global bootstrap configuration - * @see #globalBootstrap() - */ - static void globalBootstrap(Bootstrap bootstrap) { - Objects.requireNonNull(bootstrap); - InjectionServicesHolder.bootstrap(bootstrap); - } - - /** - * Get {@link InjectionServices} instance if available. The highest {@link io.helidon.common.Weighted} service will be loaded - * and returned. Remember to optionally configure any primordial {@link Bootstrap} configuration prior to the - * first call to get {@code InjectionServices}. - * - * @return the services instance - */ - static Optional injectionServices() { - return InjectionServicesHolder.injectionServices(); - } - - /** - * Short-cut for the following code block. During the first invocation the {@link Services} registry - * will be initialized. - * - *

-     * {@code
-     *   return injectionServices().orElseThrow().services();
-     * }
-     * 
- * - * @return the services instance - */ - static Services realizedServices() { - return injectionServices().orElseThrow().services(); - } - - /** - * Similar to {@link #services()}, but here if Injection is not available or the services registry has not yet been initialized - * then this method will return {@code Optional.empty()}. This is convenience for users who conditionally want to use Injection's - * service registry if it is currently available and in active use, but if not do alternative processing or allocations - * directly, etc. - * - * @return the services instance if it has already been activated and initialized, empty otherwise - */ - static Optional unrealizedServices() { - return injectionServices() - .flatMap(it -> it.services(false)); - } - - /** - * The service registry. The first call typically loads and initializes the service registry. To avoid automatic loading - * and initialization on any first request then consider using {@link #unrealizedServices()} or {@link #services(boolean)}. - * - * @return the services registry - */ - default Services services() { - return services(true).orElseThrow(); - } - - /** - * The service registry. The first call typically loads and initializes the service registry. - * - * @param initialize true to allow initialization applicable for the 1st request, false to prevent 1st call initialization - * @return the services registry if it is available and already has been initialized, empty if not yet initialized - */ - Optional services(boolean initialize); - - /** - * The governing configuration. - * - * @return the config - */ - InjectionServicesConfig config(); - - /** - * Optionally, the injector. - * - * @return the injector, or empty if not available - */ - Optional injector(); - - /** - * Attempts to perform a graceful {@link Injector#deactivate(Object, InjectorOptions)} on all managed - * service instances in the {@link Services} registry. - * Deactivation is handled within the current thread. - *

- * If the service provider does not support shutdown an empty is returned. - *

- * The default reference implementation will return a map of all service types that were deactivated to any - * throwable that was observed during that services shutdown sequence. - *

- * The order in which services are deactivated is dependent upon whether the {@link #activationLog()} is available. - * If the activation log is available, then services will be shutdown in reverse chronological order as how they - * were started. If the activation log is not enabled or found to be empty then the deactivation will be in reverse - * order of {@link RunLevel} from the highest value down to the lowest value. If two services share - * the same {@link RunLevel} value then the ordering will be based upon the implementation's comparator. - *

- * When shutdown returns, it is guaranteed that all services were shutdown, or failed to achieve shutdown. - *

- * The shutdown timeout from {@link InjectionServicesConfigBlueprint#shutdownTimeout()} will be applied as the default. - * - * @return a map of all managed service types deactivated to results of deactivation, or empty if shutdown is not supported - */ - Optional> shutdown(); - - /** - * Optionally, the service provider activation log. - * - * @return the injector, or empty if not available - */ - Optional activationLog(); - - /** - * Optionally, the metrics that are exposed by the provider implementation. - * - * @return the metrics, or empty if not available - */ - Optional metrics(); - - /** - * Optionally, the set of {@link Services} lookup criteria that were recorded. This is only available if - * {@link InjectionServicesConfig#serviceLookupCaching()} is enabled. - * - * @return the lookup criteria recorded, or empty if not available - */ - Optional> lookups(); - - /** - * Will create an activation request either to {@link Phase#ACTIVE} or limited to any - * {@link Bootstrap#limitRuntimePhase()} specified. - * - * @return the activation request - */ - static ActivationRequest createActivationRequestDefault() { - return ActivationRequest.builder().targetPhase(terminalActivationPhase()).build(); - } - - /** - * The terminal phase for activation that we should not cross. - * - * @return the terminal phase for activation - */ - static Phase terminalActivationPhase() { - Optional globalBootstrap = InjectionServices.globalBootstrap(); - if (globalBootstrap.isPresent()) { - Optional limitPhase = globalBootstrap.get().limitRuntimePhase(); - return limitPhase.orElse(Phase.ACTIVE); - } - return Phase.ACTIVE; - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectionServicesConfigBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/InjectionServicesConfigBlueprint.java deleted file mode 100644 index af673747a49..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectionServicesConfigBlueprint.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.time.Duration; -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * This is the configuration that the Injection service provider uses internally. - *

- * If left as-is a default configuration instance will be used with default values provided herein. Callers can - * optionally configure values by providing a {@link Bootstrap#config()} prior to Injection startup. The configuration provided - * will be used, and tunable configuration must be located under the key {@code inject} within the provided configuration - * element. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -@Configured(root = true, prefix = "inject") -interface InjectionServicesConfigBlueprint { - /** - * The provider implementation name. - * - * @return the provider implementation name - */ - @ConfiguredOption - Optional providerName(); - - /** - * The provider implementation version. - * - * @return the provider implementation version - */ - @ConfiguredOption - Optional providerVersion(); - - /** - * The deadlock detection timeout in millis. - * - * @return the deadlock detection timeout - */ - @ConfiguredOption("PT10S") - Duration activationDeadlockDetectionTimeout(); - - /** - * Shutdown timeout. - * - * @return shutdown timeout - */ - @ConfiguredOption("PT10S") - Duration shutdownTimeout(); - - /** - * Flag indicating whether activation logs are captured, recorded, and retained. - * - * @return the flag indicating whether activation logs are captured and retained - */ - @ConfiguredOption("false") - boolean activationLogs(); - - /** - * Flag indicating whether service lookups (i.e., via {@link Services#lookup}) are cached. - * - * @return the flag indicating whether service lookups are cached - */ - @ConfiguredOption("false") - boolean serviceLookupCaching(); - - /** - * Flag indicating whether the services registry permits dynamic behavior. The default - * implementation of Injection supports dynamic (see {@link #supportsDynamic()}), but does not permit it by default. - * - * @return the flag indicating whether the services registry supports dynamic updates of the service registry - */ - @ConfiguredOption("false") - boolean permitsDynamic(); - - /** - * Flag indicating whether the services registry supports dynamic behavior. Note that - * if the provider does not support this flag then permitting it via {@link #permitsDynamic()} will have no affect. The - * default implementation of Injection supports dynamic, but does not permit it by default. - * - * @return the flag indicating whether the services registry supports dynamic updates of the service registry post - * startup - */ - @ConfiguredOption("true") - boolean supportsDynamic(); - - /** - * Flag indicating whether reflection is permitted. The default implementation of Injection - * supports reflection at compile-time only, and is not controlled by this flag directly. - * - * @return the flag indicating whether the provider is permitted to use reflection for normal runtime usage - */ - @ConfiguredOption("false") - boolean permitsReflection(); - - /** - * Flag indicating whether the reflection is supported. Note that if the provider does not support this - * flag then permitting it via {@link #permitsReflection()} will have no affect. The default implementation of Injection supports - * reflection only during compile-time operations using the Injection maven-plugin. - * - * @return the flag indicating whether reflection is supported during runtime operations - */ - @ConfiguredOption("false") - boolean supportsReflection(); - - /** - * Flag indicating whether compile-time generated {@link Application}'s should be used at Injection's startup initialization. - * Setting - * this value to false will have no affect if the underlying provider does not support compile-time generation via - * {@link #supportsCompileTime()}. - * - * @return the flag indicating whether the provider is permitted to use Application generated code from compile-time - * @see Application - * @see Activator - */ - @ConfiguredOption("true") - boolean usesCompileTimeApplications(); - - /** - * Flag indicating whether compile-time generated {@link ModuleComponent}'s should be used at Injection's startup - * initialization. Setting this value to false will have no affect if the underlying provider does not support compile-time - * generation via {@link #supportsCompileTime()}. - * - * @return the flag indicating whether the provider is permitted to use Application generated code from compile-time - * @see ModuleComponent - * @see Activator - */ - @ConfiguredOption("true") - boolean usesCompileTimeModules(); - - /** - * Flag indicating whether the dependency injection model for the {@link Application} and - * {@link Activator} is capable for being produced at compile-time, and therefore used/loaded during runtime operations. - * - * @return the flag indicating whether the provider supports compile-time code generation of DI artifacts - */ - @ConfiguredOption("true") - boolean supportsCompileTime(); - - /** - * Flag indicating whether jsr330 specification will be used and enforced. - * - * @return the flag indicating whether strict jsr330 specification will be enforced - */ - @ConfiguredOption("false") - boolean usesJsr330(); - - /** - * Flag indicating whether jsr330 is supported by the provider implementation. - * - * @return the flag indicating whether the provider supports the jsr330 specification - */ - @ConfiguredOption("true") - boolean supportsJsr330(); - - /** - * Flag indicating whether jsr330 is supported by the provider implementation for the use on static injection points. - * - * @return the flag indicating whether the provider supports the jsr330 specification for the use of static injection points - */ - @ConfiguredOption("false") - boolean supportsJsr330Statics(); - - /** - * Flag indicating whether jsr330 is supported by the provider implementation for the use on private injection points. - * - * @return the flag indicating whether the provider supports the jsr330 specification for the use of private injection points - */ - @ConfiguredOption("false") - boolean supportsJsr330Privates(); - - /** - * Flag indicating whether contextual lookup is supported via {@link Services#contextualServices(InjectionPointInfo)}. - * - * @return the flag indicating whether the provider supports contextual lookup - */ - @ConfiguredOption("false") - boolean supportsContextualLookup(); - - /** - * Whether debug is enabled. - * Defaults to false, can be overridden using system property {@link InjectionServices#TAG_DEBUG}. - * - * @return if debug should be enabled - */ - @ConfiguredOption - Optional debug(); - - /** - * Uses configured {@link #debug()}, or attempts to discover if debug should be used if not configured. - * - * @return whether to debug - */ - default boolean shouldDebug() { - return debug().orElseGet(() -> Boolean.getBoolean(InjectionServices.TAG_DEBUG)); - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectionServicesHolder.java b/inject/api/src/main/java/io/helidon/inject/api/InjectionServicesHolder.java deleted file mode 100644 index c991adfbc32..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectionServicesHolder.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.inject.spi.InjectionServicesProvider; - -/** - * The holder for the globally active {@link InjectionServices} singleton instance, as well as its associated - * {@link Bootstrap} primordial configuration. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -// exposed in the testing module as non deprecated -public abstract class InjectionServicesHolder { - /** - * Helpful hint to give developers needing to see more debug info. - */ - public static final String DEBUG_HINT = "use the (-D and/or -A) tag 'inject.debug=true' to see full trace output."; - - private static final AtomicReference BOOTSTRAP = new AtomicReference<>(); - private static final AtomicReference INSTANCE = new AtomicReference<>(); - private static final List RESETTABLES = new ArrayList<>(); - private static final Lock RESETTABLES_LOCK = new ReentrantLock(); - - /** - * Default Constructor. - * - * @deprecated use {@link InjectionServices#injectionServices()} or {@link InjectionServices#globalBootstrap()}. - */ - // exposed in the testing module as non deprecated - @Deprecated - protected InjectionServicesHolder() { - } - - /** - * Returns the global Injection services instance. The returned service instance will be initialized with any bootstrap - * configuration that was previously established. - * - * @return the loaded global services instance - */ - static Optional injectionServices() { - if (INSTANCE.get() == null) { - INSTANCE.compareAndSet(null, new ProviderAndServicesTuple(load())); - if (INSTANCE.get().injectionServices == null) { - System.getLogger(InjectionServices.class.getName()) - .log(System.Logger.Level.WARNING, - "Injection runtime services not detected on the classpath"); - } - } - return Optional.ofNullable(INSTANCE.get().injectionServices); - } - - /** - * Resets the bootstrap state. - */ - protected static void reset() { - ProviderAndServicesTuple instance = INSTANCE.get(); - if (instance != null) { - instance.reset(); - } - - try { - RESETTABLES_LOCK.lock(); - RESETTABLES.forEach(it -> it.reset(true)); - RESETTABLES.clear(); - } finally { - RESETTABLES_LOCK.unlock(); - } - - INSTANCE.set(null); - BOOTSTRAP.set(null); - } - - /** - * Register a resettable instance. When {@link #reset()} is called, this instance is removed from the list. - * - * @param instance resettable type that can be reset during testing - */ - protected static void addResettable(Resettable instance) { - try { - RESETTABLES_LOCK.lock(); - RESETTABLES.add(instance); - } finally { - RESETTABLES_LOCK.unlock(); - } - - } - - static void bootstrap(Bootstrap bootstrap) { - Objects.requireNonNull(bootstrap); - InternalBootstrap iBootstrap = InternalBootstrap.builder().bootStrap(bootstrap).build(); - - InternalBootstrap existing = BOOTSTRAP.compareAndExchange(null, iBootstrap); - if (existing != null) { - CallingContext callingContext = existing.callingContext().orElse(null); - StackTraceElement[] trace = (callingContext == null) - ? new StackTraceElement[] {} - : callingContext.stackTrace().orElse(null); - if (trace != null && trace.length > 0) { - throw new IllegalStateException( - "bootstrap was previously set from this code path:\n" + prettyPrintStackTraceOf(trace) - + "; module name is '" + callingContext.moduleName().orElse("undefined") + "'"); - } - throw new IllegalStateException("The bootstrap has already been set - " + DEBUG_HINT); - } - } - - static Optional bootstrap(boolean assignIfNeeded) { - if (assignIfNeeded) { - InternalBootstrap iBootstrap = InternalBootstrap.create(); - BOOTSTRAP.compareAndSet(null, iBootstrap); - } - - InternalBootstrap iBootstrap = BOOTSTRAP.get(); - return Optional.ofNullable(iBootstrap) - .flatMap(InternalBootstrap::bootStrap); - } - - /** - * Returns a stack trace as a list of strings. - * - * @param trace the trace - * @return the list of strings for the stack trace - */ - static List stackTraceOf(StackTraceElement[] trace) { - List result = new ArrayList<>(); - for (StackTraceElement e : trace) { - result.add(e.toString()); - } - return result; - } - - /** - * Returns a stack trace as a CRLF joined string. - * - * @param trace the trace - * @return the stringified stack trace - */ - static String prettyPrintStackTraceOf(StackTraceElement[] trace) { - return String.join("\n", stackTraceOf(trace)); - } - - private static Optional load() { - return HelidonServiceLoader.create(ServiceLoader.load(InjectionServicesProvider.class, - InjectionServicesProvider.class.getClassLoader())) - .asList() - .stream() - .findFirst(); - } - - // we need to keep the provider and the instance the provider creates together as one entity - private static class ProviderAndServicesTuple { - private final InjectionServicesProvider provider; - private final InjectionServices injectionServices; - - private ProviderAndServicesTuple(Optional provider) { - this.provider = provider.orElse(null); - this.injectionServices = provider.isPresent() - ? this.provider.services(bootstrap(true) - .orElseThrow(() -> new InjectionException("Failed to assign bootstrap"))) - : null; - } - - private void reset() { - if (provider instanceof Resettable) { - ((Resettable) provider).reset(true); - } else if (injectionServices instanceof Resettable) { - ((Resettable) injectionServices).reset(true); - } - } - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Injector.java b/inject/api/src/main/java/io/helidon/inject/api/Injector.java deleted file mode 100644 index 24026dd6461..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Injector.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Used to perform programmatic activation and injection. - *

- * Note that the reference implementation of Injection only performs non-reflective, compile-time generation of service activators - * for services that it manages. This Injector contract is mainly provided in order to allow other library extension - * implementations to extend the model to perform other types of injection point resolution. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface Injector { - - /** - * The strategy the injector should attempt to apply. The reference implementation for Injection provider only handles - * {@link Injector.Strategy#ACTIVATOR} type. - */ - enum Strategy { - - /** - * Activator based implies compile-time injection strategy. This is the preferred / default strategy. - */ - ACTIVATOR, - - /** - * Reflection based implies runtime injection strategy. Note: This is available for other 3rd parties of Injection that - * choose to use reflection as a strategy. - */ - REFLECTION, - - /** - * Any. Defers the strategy to the provider implementation's capabilities and configuration. - */ - ANY - - } - - /** - * Called to activate and inject a manage service instance or service provider, putting it into - * {@link Phase#ACTIVE}. - * - * @param serviceOrServiceProvider the target instance or service provider being activated and injected - * @param opts the injector options - * @param the managed service type - * @return the result of the activation - * @throws InjectionServiceProviderException if an injection or activation problem occurs - * @see Activator - */ - ActivationResult activateInject(T serviceOrServiceProvider, - InjectorOptions opts) throws InjectionServiceProviderException; - - /** - * Called to deactivate a managed service or service provider, putting it into {@link Phase#DESTROYED}. - * If a managed service has a {@link jakarta.annotation.PreDestroy} annotated method then it will be called during - * this lifecycle event. - * - * @param serviceOrServiceProvider the service provider or instance registered and being managed - * @param opts the injector options - * @param the managed service type - * @return the result of the deactivation - * @throws InjectionServiceProviderException if a problem occurs - * @see DeActivator - */ - ActivationResult deactivate(T serviceOrServiceProvider, - InjectorOptions opts) throws InjectionServiceProviderException; - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectorOptionsBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/InjectorOptionsBlueprint.java deleted file mode 100644 index 412835ace5e..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectorOptionsBlueprint.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Provides optional, contextual tunings to the {@link Injector}. - * - * @see Injector - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint(decorator = InjectorOptionsBlueprint.BuilderDecorator.class) -interface InjectorOptionsBlueprint { - /** - * The strategy the injector should apply. The default is {@link Injector.Strategy#ANY}. - * - * @return the injector strategy to use - */ - @ConfiguredOption("ANY") - Injector.Strategy strategy(); - - /** - * Optionally, customized activator options to use for the {@link Activator}. - * - * @return activator options, or leave blank to use defaults - */ - ActivationRequest activationRequest(); - - - /** - * This will ensure that the activation request is populated. - */ - class BuilderDecorator implements Prototype.BuilderDecorator> { - BuilderDecorator() { - } - - @Override - public void decorate(InjectorOptions.BuilderBase target) { - if (target.activationRequest().isEmpty()) { - target.activationRequest(InjectionServices.createActivationRequestDefault()); - } - } - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Intercepted.java b/inject/api/src/main/java/io/helidon/inject/api/Intercepted.java deleted file mode 100644 index 38f2ab04c0b..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Intercepted.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -/** - * Indicates that type identified by {@link #value()} is being intercepted. - * - * @see Interceptor - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Documented -@Retention(RetentionPolicy.CLASS) -@Inherited -@Qualifier -@Target(java.lang.annotation.ElementType.TYPE) -public @interface Intercepted { - - /** - * The target being intercepted. - * - * @return the target class being intercepted - */ - Class value(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InterceptedTrigger.java b/inject/api/src/main/java/io/helidon/inject/api/InterceptedTrigger.java deleted file mode 100644 index 35247ed707c..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InterceptedTrigger.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Meta-annotation for an annotation that will trigger services annotated with it to become intercepted. - * - * @see Interceptor - * @see Intercepted - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Documented -@Retention(RetentionPolicy.CLASS) -@Target(ElementType.ANNOTATION_TYPE) -public @interface InterceptedTrigger { - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Interceptor.java b/inject/api/src/main/java/io/helidon/inject/api/Interceptor.java deleted file mode 100644 index d7eeae240f5..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Interceptor.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Implementors of this contract must be {@link jakarta.inject.Named} according to the {@link Intercepted} - * annotation they support. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface Interceptor { - - /** - * Called during interception of the target V. The implementation typically should finish with the call to - * {@link Interceptor.Chain#proceed}. - * - * @param ctx the invocation context - * @param chain the chain to call proceed on - * @param args the arguments to the call - * @param the return value type (or {@link Void} for void method elements) - * @return the return value to the caller - * @throws InvocationException if there are errors during invocation chain processing - */ - V proceed(InvocationContext ctx, Chain chain, Object... args); - - - /** - * Represents the next in line for interception, terminating with a call to the wrapped service provider. - * - * @param the return value - */ - interface Chain { - /** - * Call the next interceptor in line, or finishing with the call to the service provider being intercepted. - * Note that that arguments are passed by reference to each interceptor ultimately leading up to the final - * call to the underlying intercepted target. Callers can mutate the arguments passed directly on the provided array - * instance. - * - * @param args the arguments passed - * @return the result of the call - * @throws InvocationException if there are errors during invocation chain processing - */ - V proceed(Object[] args); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InternalBootstrapBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/InternalBootstrapBlueprint.java deleted file mode 100644 index a16961e1a6a..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InternalBootstrapBlueprint.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; - -/** - * Internal bootstrap is what we store when {@link InjectionServices#globalBootstrap(Bootstrap)} is used. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint(decorator = InternalBootstrapBlueprint.BuilderDecorator.class) -interface InternalBootstrapBlueprint { - - /** - * The user established bootstrap. - * - * @return user established bootstrap - */ - Optional bootStrap(); - - /** - * Only populated when {@link InjectionServices#TAG_DEBUG} is set. - * - * @return the calling context - */ - Optional callingContext(); - - class BuilderDecorator implements Prototype.BuilderDecorator> { - @Override - public void decorate(InternalBootstrap.BuilderBase target) { - if (target.bootStrap().isEmpty()) { - target.bootStrap(Bootstrap.create()); - } - } - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InvocationContextBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/InvocationContextBlueprint.java deleted file mode 100644 index 72af2dd658b..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InvocationContextBlueprint.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.List; -import java.util.Map; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; - -import jakarta.inject.Provider; - -/** - * Used by {@link Interceptor}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface InvocationContextBlueprint { - - /** - * The service provider being intercepted. - * - * @return the service provider being intercepted - */ - ServiceProvider serviceProvider(); - - /** - * The service type name for the root service provider. - * - * @return the service type name for the root service provider - */ - TypeName serviceTypeName(); - - /** - * The annotations on the enclosing type. - * - * @return the annotations on the enclosing type - */ - List classAnnotations(); - - /** - * The element info represents the method (or the constructor) being invoked. - * - * @return the element info represents the method (or the constructor) being invoked - */ - TypedElementInfo elementInfo(); - - /** - * The method/element argument info. - * - * @return the method/element argument info - */ - List elementArgInfo(); - - /** - * The interceptor chain. - * - * @return the interceptor chain - */ - List> interceptors(); - - /** - * The contextual info that can be shared between interceptors. - * - * @return the read/write contextual data that is passed between each chained interceptor - */ - Map contextData(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/InvocationException.java b/inject/api/src/main/java/io/helidon/inject/api/InvocationException.java deleted file mode 100644 index 854da302213..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/InvocationException.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Wraps any checked exceptions that are thrown during the {@link Interceptor} invocations. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class InvocationException extends InjectionServiceProviderException { - - /** - * Tracks whether the target being intercepted was called once successfully - meaning that the target was called and it - * did not result in any exception being thrown. - */ - private final boolean targetWasCalled; - - /** - * Constructor. - * - * @param msg the message - * @param targetWasCalled set to true if the target of interception was ultimately called successfully - */ - public InvocationException(String msg, - boolean targetWasCalled) { - super(msg); - this.targetWasCalled = targetWasCalled; - } - /** - * Constructor. - * - * @param msg the message - * @param cause the root cause - * @param targetWasCalled set to true if the target of interception was ultimately called successfully - */ - public InvocationException(String msg, - Throwable cause, - boolean targetWasCalled) { - super(msg, cause); - this.targetWasCalled = targetWasCalled; - } - /** - * Constructor. - * - * @param msg the message - * @param cause the root cause - * @param serviceProvider the service provider - * @param targetWasCalled set to true if the target of interception was ultimately called successfully - */ - public InvocationException(String msg, - Throwable cause, - ServiceProvider serviceProvider, - boolean targetWasCalled) { - super(msg, cause, serviceProvider); - this.targetWasCalled = targetWasCalled; - } - - /** - * Returns true if the final target of interception was ultimately called. - * - * @return if the target being intercepted was ultimately called successfully - */ - public boolean targetWasCalled() { - return targetWasCalled; - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/MetricsBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/MetricsBlueprint.java deleted file mode 100644 index 953a657de8e..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/MetricsBlueprint.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; - -/** - * Metrics. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface MetricsBlueprint { - - /** - * The total service count in the registry. - * - * @return total service count - */ - Optional serviceCount(); - - /** - * The total number of {@code Services::lookup()} calls since jvm start, or since last reset. - * - * @return lookup count - */ - Optional lookupCount(); - - /** - * The total number of {@code Services::lookup()} calls that were attempted against the lookup cache. This will be empty - * if caching is disabled. - * - * @see InjectionServicesConfig - * @return cache lookup count - */ - Optional cacheLookupCount(); - - /** - * The total number of {@code Services:lookup()} calls that were successfully resolved via cache. This will be a value less - * than or equal to {@link #cacheLookupCount()}. - * - * @return cache hit count - */ - Optional cacheHitCount(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ModuleComponent.java b/inject/api/src/main/java/io/helidon/inject/api/ModuleComponent.java deleted file mode 100644 index 8a214bc12f6..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ModuleComponent.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -/** - * Provides aggregation of services to the "containing" (jar) module. - *

- * Implementations of this contract are normally code generated, although then can be programmatically written by the developer - * for special cases. - *

- * Note: instances of this type are not eligible for injection. - * - * @see Application - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface ModuleComponent extends OptionallyNamed { - - /** - * Called by the provider implementation at bootstrapping time to bind all services / service providers to the - * service registry. - * - * @param binder the binder used to register the services to the registry - */ - void configure(ServiceBinder binder); - - @Override - default Optional named() { - return Optional.empty(); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/OptionallyNamed.java b/inject/api/src/main/java/io/helidon/inject/api/OptionallyNamed.java deleted file mode 100644 index d21a90bc42f..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/OptionallyNamed.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -/** - * Provides a means to identify if the instance is optionally named. - * - * @see jakarta.inject.Named - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface OptionallyNamed { - - /** - * The optional name for this instance. - * - * @return the name associated with this instance or empty if not available or known - */ - Optional named(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Phase.java b/inject/api/src/main/java/io/helidon/inject/api/Phase.java deleted file mode 100644 index 0611bbe31b6..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Phase.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Forms a progression of full activation and deactivation. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public enum Phase { - - /** - * Starting state before anything happens activation-wise. - */ - INIT(false), - - /** - * Planned to be activated. - */ - PENDING(true), - - /** - * Starting to be activated. - */ - ACTIVATION_STARTING(true), - - /** - * Gathering dependencies. - */ - GATHERING_DEPENDENCIES(true), - - /** - * Constructing. - */ - CONSTRUCTING(true), - - /** - * Injecting (fields then methods). - */ - INJECTING(true), - - /** - * Calling any post construct method. - */ - POST_CONSTRUCTING(true), - - /** - * Finishing post construct method. - */ - ACTIVATION_FINISHING(true), - - /** - * Service is active. - */ - ACTIVE(true), - - /** - * Called after all modules and services loaded into the service registry. - */ - POST_BIND_ALL_MODULES(true), - - /** - * Called after {@link #POST_BIND_ALL_MODULES} to resolve any latent bindings, prior to {@link #SERVICES_READY}. - */ - FINAL_RESOLVE(true), - - /** - * The service registry is fully populated and ready. - */ - SERVICES_READY(true), - - /** - * About to call pre-destroy. - */ - PRE_DESTROYING(true), - - /** - * Destroyed (after calling any pre-destroy). - */ - DESTROYED(false); - - /** - * True if this phase is eligible for deactivation/shutdown. - */ - private final boolean eligibleForDeactivation; - - /** - * Determines whether this phase passes the gate for whether deactivation (PreDestroy) can be called. - * - * @return true if this phase is eligible to be included in shutdown processing - * @see InjectionServices#shutdown() - */ - public boolean eligibleForDeactivation() { - return eligibleForDeactivation; - } - - Phase(boolean eligibleForDeactivation) { - this.eligibleForDeactivation = eligibleForDeactivation; - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/PostConstructMethod.java b/inject/api/src/main/java/io/helidon/inject/api/PostConstructMethod.java deleted file mode 100644 index 48e95a65247..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/PostConstructMethod.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Represents the {@link jakarta.annotation.PostConstruct} method. - * - * @see Activator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@FunctionalInterface -public interface PostConstructMethod { - - /** - * Represents the post-construct method. - */ - void postConstruct(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/PreDestroyMethod.java b/inject/api/src/main/java/io/helidon/inject/api/PreDestroyMethod.java deleted file mode 100644 index c9fe55d9dc4..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/PreDestroyMethod.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Represents the {@link jakarta.annotation.PreDestroy} method. - * - * @see DeActivator - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@FunctionalInterface -public interface PreDestroyMethod { - - /** - * Represents the pre destroy method. - */ - void preDestroy(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/QualifierBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/QualifierBlueprint.java deleted file mode 100644 index 2946aeb3905..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/QualifierBlueprint.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; - -import jakarta.inject.Named; - -/** - * Represents a qualifier annotation (a specific case of annotations, annotated with {@link jakarta.inject.Qualifier}. - * - * @see jakarta.inject.Qualifier - * @see CommonQualifiers - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -@Prototype.CustomMethods(QualifierBlueprint.QualifierMethods.class) -interface QualifierBlueprint extends Annotation { - /** - * The type name for {@link ClassNamed}. - */ - TypeName CLASS_NAMED = TypeName.create(ClassNamed.class); - - /** - * The qualifier annotation type name. - * - * @return the qualifier/annotation type name - */ - default String qualifierTypeName() { - return typeName().name(); - } - - final class QualifierMethods { - private QualifierMethods() { - } - - /** - * Creates a qualifier from an annotation. - * - * @param qualifierType the qualifier type - * @return qualifier - */ - @Prototype.FactoryMethod - static Qualifier create(Class qualifierType) { - Objects.requireNonNull(qualifierType); - TypeName qualifierTypeName = maybeNamed(qualifierType.getName()); - return Qualifier.builder().typeName(qualifierTypeName).build(); - } - - /** - * Creates a qualifier with a value from an annotation. - * - * @param qualifierType the qualifier type - * @param value the value property - * @return qualifier - */ - @Prototype.FactoryMethod - static Qualifier create(Class qualifierType, String value) { - Objects.requireNonNull(qualifierType); - TypeName qualifierTypeName = maybeNamed(qualifierType.getName()); - return Qualifier.builder() - .typeName(qualifierTypeName) - .putValue("value", value) - .build(); - } - - /** - * Creates a qualifier from an annotation. - * - * @param annotation the qualifier annotation - * @return qualifier - */ - @Prototype.FactoryMethod - static Qualifier create(Annotation annotation) { - Objects.requireNonNull(annotation); - if (annotation instanceof Qualifier qualifier) { - return qualifier; - } - return Qualifier.builder() - .typeName(maybeNamed(annotation.typeName())) - .values(removeEmptyProperties(annotation.values())) - .build(); - } - - /** - * Creates a {@link jakarta.inject.Named} qualifier. - * - * @param name the name - * @return named qualifier - */ - @Prototype.FactoryMethod - static Qualifier createNamed(String name) { - Objects.requireNonNull(name); - return Qualifier.builder() - .typeName(CommonQualifiers.NAMED) - .value(name) - .build(); - } - - /** - * Creates a {@link jakarta.inject.Named} qualifier. - * - * @param name the name - * @return named qualifier - */ - @Prototype.FactoryMethod - static Qualifier createNamed(Named name) { - Objects.requireNonNull(name); - Qualifier.Builder builder = Qualifier.builder() - .typeName(CommonQualifiers.NAMED); - if (!name.value().isEmpty()) { - builder.value(name.value()); - } - return builder.build(); - } - - /** - * Creates a {@link jakarta.inject.Named} qualifier. - * - * @param name the name - * @return named qualifier - */ - @Prototype.FactoryMethod - static Qualifier createNamed(ClassNamed name) { - Objects.requireNonNull(name); - return Qualifier.builder() - .typeName(CommonQualifiers.NAMED) - .value(name.value().getName()) - .build(); - } - - /** - * Creates a {@link jakarta.inject.Named} qualifier from a class name. - * - * @param className class whose name will be used - * @return named qualifier - */ - @Prototype.FactoryMethod - static Qualifier createNamed(Class className) { - Objects.requireNonNull(className); - return Qualifier.builder() - .typeName(CommonQualifiers.NAMED) - .value(className.getName()) - .build(); - } - - private static TypeName maybeNamed(String qualifierTypeName) { - if (qualifierTypeName.equals(ClassNamed.class.getName())) { - return CommonQualifiers.NAMED; - } - return TypeName.create(qualifierTypeName); - } - - private static TypeName maybeNamed(TypeName qualifierType) { - if (CLASS_NAMED.equals(qualifierType)) { - return CommonQualifiers.NAMED; - } - return qualifierType; - } - - private static Map removeEmptyProperties(Map values) { - HashMap result = new HashMap<>(values); - result.entrySet().removeIf(entry -> { - Object value = entry.getValue(); - return value instanceof String str && str.isBlank(); - }); - return result; - } - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Qualifiers.java b/inject/api/src/main/java/io/helidon/inject/api/Qualifiers.java deleted file mode 100644 index d6535e61732..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Qualifiers.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Collection; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.common.types.Annotation; - -/** - * Utility methods for qualifiers. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public final class Qualifiers { - private Qualifiers() { - } - - /** - * Matches qualifier collections. - * - * @param src the target service info to evaluate - * @param criteria the criteria to compare against - * @return true if the criteria provided matches this instance - */ - public static boolean matchesQualifiers(Collection src, - Collection criteria) { - if (criteria.isEmpty()) { - return true; - } - - if (src.isEmpty()) { - return false; - } - - if (src.contains(CommonQualifiers.WILDCARD_NAMED)) { - return true; - } - - for (Qualifier criteriaQualifier : criteria) { - if (src.contains(criteriaQualifier)) { - // NOP; - continue; - } else if (criteriaQualifier.typeName().equals(CommonQualifiers.NAMED)) { - if (criteriaQualifier.equals(CommonQualifiers.WILDCARD_NAMED) - || criteriaQualifier.value().isEmpty()) { - // any Named qualifier will match ... - boolean hasSameTypeAsCriteria = src.stream() - .anyMatch(q -> q.typeName().equals(criteriaQualifier.typeName())); - if (hasSameTypeAsCriteria) { - continue; - } - } else if (src.contains(CommonQualifiers.WILDCARD_NAMED)) { - continue; - } - return false; - } else if (criteriaQualifier.value().isEmpty()) { - Set sameTypeAsCriteriaSet = src.stream() - .filter(q -> q.typeName().equals(criteriaQualifier.typeName())) - .collect(Collectors.toSet()); - if (sameTypeAsCriteriaSet.isEmpty()) { - return false; - } - } else { - return false; - } - } - - return true; - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Resettable.java b/inject/api/src/main/java/io/helidon/inject/api/Resettable.java deleted file mode 100644 index 379b3f4fee9..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Resettable.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Implementors of this contract are capable of resetting the state of itself (i.e., clears cache, log entries, etc.). - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@FunctionalInterface -public interface Resettable { - - /** - * Resets the state of this object. - * - * @param deep true to iterate over any contained objects, to reflect the reset into the retained object - * @return returns true if the state was changed - */ - boolean reset(boolean deep); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/RunLevel.java b/inject/api/src/main/java/io/helidon/inject/api/RunLevel.java deleted file mode 100644 index d03f1131963..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/RunLevel.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.TYPE; - -/** - * Indicates the desired startup sequence for a service class. This is not used internally by Injection, but is available as a - * convenience to the caller in support for a specific startup sequence for service activations. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Documented -@Retention(RetentionPolicy.CLASS) -@Target(TYPE) -public @interface RunLevel { - - /** - * Represents an eager singleton that should be started at "startup". Note, however, that callers control the actual - * activation for these services, not the framework itself, as shown below: - *

-     * {@code
-     * List> startupServices = services
-     *               .lookup(ServiceInfoCriteria.builder().runLevel(RunLevel.STARTUP).build());
-     *       startupServices.stream().forEach(ServiceProvider::get);
-     * }
-     * 
- */ - int STARTUP = 10; - - /** - * Anything > 0 is left to the underlying provider implementation's discretion for meaning; this is just a default for - * something that is deemed "other than startup". - */ - int NORMAL = 100; - - /** - * The service ranking applied when not declared explicitly. - * - * @return the startup int value, defaulting to {@link #NORMAL} - */ - int value() default NORMAL; - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceBinder.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceBinder.java deleted file mode 100644 index 492dec7d32c..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceBinder.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Responsible for binding service providers to the service registry. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ServiceBinder { - - /** - * Bind a service provider instance into the backing {@link Services} service registry. - * - * @param serviceProvider the service provider to bind into the service registry - */ - void bind(ServiceProvider serviceProvider); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBasicsBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBasicsBlueprint.java deleted file mode 100644 index 5742dbeedc6..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBasicsBlueprint.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.Weighted; -import io.helidon.common.types.TypeName; - -/** - * Basic service info that describes a service provider type. - * - * @see ServiceInfo - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -@Prototype.CustomMethods(ServiceInfoBasicsBlueprint.CustomMethods.class) -interface ServiceInfoBasicsBlueprint { - - /** - * Default weight for any internal Injection service component. It is defined to be - * {@link io.helidon.common.Weighted#DEFAULT_WEIGHT} {@code - 1} in order to allow any other service implementation to - * naturally have a higher weight (since it will use the {@code DEFAULT_WEIGHT} unless explicitly overridden. - */ - double DEFAULT_INJECT_WEIGHT = Weighted.DEFAULT_WEIGHT - 1; - - /** - * The managed service implementation {@link Class}. - * - * @return the service type name - */ - TypeName serviceTypeName(); - - /** - * The managed service assigned Scope's. - * - * @return the service scope type name - */ - @Option.Singular - Set scopeTypeNames(); - - /** - * The managed service assigned Qualifier's. - * - * @return the service qualifiers - */ - @Option.Singular - Set qualifiers(); - - /** - * The managed services advertised types (i.e., typically its interfaces). - * - * @see ExternalContracts - * @return the service contracts implemented - */ - @Option.Singular("contractImplemented") - Set contractsImplemented(); - - /** - * The optional {@link RunLevel} ascribed to the service. - * - * @return the service's run level - * @see #realizedRunLevel() - */ - Optional declaredRunLevel(); - - /** - * The realized run level will use the default run level if no run level was specified directly. - * - * @return the realized run level - * @see #declaredRunLevel() - */ - default int realizedRunLevel() { - return declaredRunLevel().orElse(RunLevel.NORMAL); - } - - /** - * Weight that was declared on the type itself. - * - * @return the declared weight - * @see #realizedWeight() - */ - Optional declaredWeight(); - - /** - * The realized weight will use {@link io.helidon.common.Weighted#DEFAULT_WEIGHT} if no weight was specified directly. - * - * @return the realized weight - * @see #declaredWeight() - */ - default double realizedWeight() { - return declaredWeight().orElse(Weighted.DEFAULT_WEIGHT); - } - - final class CustomMethods { - private CustomMethods() { - } - - /** - * The managed service implementation type name. - * @param builder the builder instance - * @param type type of the service - */ - @Prototype.BuilderMethod - static void serviceTypeName(ServiceInfoBasics.BuilderBase builder, Class type) { - builder.serviceTypeName(TypeName.create(type)); - } - - /** - * Add contract implemented. - * - * @param builder the builder instance - * @param type type of the service - */ - @Prototype.BuilderMethod - static void addContractImplemented(ServiceInfoBasics.BuilderBase builder, Class type) { - builder.addContractImplemented(TypeName.create(type)); - } - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBlueprint.java deleted file mode 100644 index 06f6f9ede95..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBlueprint.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * Describes a managed service or injection point. - * - * @see Services - * @see ServiceInfoCriteria - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint(decorator = ServiceInfoBuildDecorator.class) -@Prototype.CustomMethods(ServiceInfoBlueprint.CustomMethods.class) -interface ServiceInfoBlueprint extends ServiceInfoBasicsBlueprint, ServiceInfoBasics { - - /** - * The managed services external contracts / interfaces. These should also be contained within - * {@link #contractsImplemented()}. External contracts are from other modules other than the module containing - * the implementation typically. - * - * @see ExternalContracts - * @return the service external contracts implemented - */ - @Option.Singular("externalContractImplemented") - Set externalContractsImplemented(); - - /** - * The management agent (i.e., the activator) that is responsible for creating and activating - typically build-time created. - * - * @return the activator type name - */ - Optional activatorTypeName(); - - /** - * The name of the ascribed module, if known. - * - * @return the module name - */ - Optional moduleName(); - - /** - * Determines whether this service info matches the criteria for injection. - * Matches is a looser form of equality check than {@code equals()}. If a service matches criteria - * it is generally assumed to be viable for assignability. - * - * @param criteria the criteria to compare against - * @return true if the criteria provided matches this instance - */ - // internal note: it is unfortunate that we have a matches() here as well as in ServiceInfo. This is what happened - // when we split ServiceInfo into ServiceInfoCriteria. Sometimes we need ServiceInfo.matches(criteria), and other times - // ServiceInfoCriteria.matches(criteria). - default boolean matches(ServiceInfoCriteria criteria) { - if (criteria == InjectionServices.EMPTY_CRITERIA) { - return true; - } - - boolean matches = matches(serviceTypeName(), criteria.serviceTypeName()); - if (matches && criteria.serviceTypeName().isEmpty()) { - matches = contractsImplemented().containsAll(criteria.contractsImplemented()) - || criteria.contractsImplemented().contains(serviceTypeName()); - } - return matches - && scopeTypeNames().containsAll(criteria.scopeTypeNames()) - && Qualifiers.matchesQualifiers(qualifiers(), criteria.qualifiers()) - && matches(activatorTypeName(), criteria.activatorTypeName()) - && matchesWeight(this, criteria) - && matches(realizedRunLevel(), criteria.runLevel()) - && matches(moduleName(), criteria.moduleName()); - } - - private static boolean matches(Object src, - Optional criteria) { - if (criteria.isEmpty()) { - return true; - } - - return Objects.equals(src, criteria.get()); - } - - /** - * Weight matching is always less or equal to criteria specified. - * - * @param src the item being considered - * @param criteria the criteria - * @return true if there is a match - */ - private static boolean matchesWeight(ServiceInfoBasics src, - ServiceInfoCriteria criteria) { - if (criteria.weight().isEmpty()) { - return true; - } - - Double srcWeight = src.realizedWeight(); - return (srcWeight.compareTo(criteria.weight().get()) <= 0); - } - - final class CustomMethods { - private CustomMethods() { - } - - /** - * Create a builder of service info from its basics counterpart. - * - * @param prototype instance to copy - * @return a new builder with data from prototype - */ - @Prototype.FactoryMethod - static ServiceInfo.Builder builder(ServiceInfoBasics prototype) { - Objects.requireNonNull(prototype); - if (prototype instanceof ServiceInfo serviceInfo) { - return ServiceInfo.builder(serviceInfo); - } - return ServiceInfo.builder() - .serviceTypeName(prototype.serviceTypeName()) - .scopeTypeNames(prototype.scopeTypeNames()) - .qualifiers(prototype.qualifiers()) - .contractsImplemented(prototype.contractsImplemented()) - .declaredRunLevel(prototype.declaredRunLevel()) - .declaredWeight(prototype.declaredWeight()); - } - - /** - * Add external contract implemented. - * - * @param builder the builder instance - * @param type type of the external contract - */ - @Prototype.BuilderMethod - static void addExternalContractImplemented(ServiceInfo.BuilderBase builder, Class type) { - builder.addExternalContractImplemented(TypeName.create(type)); - } - - /** - * Activator type. - * - * @param builder the builder instance - * @param type type of the activator - */ - @Prototype.BuilderMethod - static void activatorTypeName(ServiceInfo.BuilderBase builder, Class type) { - builder.activatorTypeName(TypeName.create(type)); - } - - /** - * Add a scope type. - * - * @param builder the builder instance - * @param type type of the scope - */ - @Prototype.BuilderMethod - static void addScopeTypeName(ServiceInfo.BuilderBase builder, Class type) { - builder.addScopeTypeName(TypeName.create(type)); - } - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildDecorator.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildDecorator.java deleted file mode 100644 index 8499db71033..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildDecorator.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import io.helidon.builder.api.Prototype; - -/** - * Ensures that all external contracts are also treated as normal contracts, etc. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -class ServiceInfoBuildDecorator implements Prototype.BuilderDecorator> { - - @Override - public void decorate(ServiceInfo.BuilderBase target) { - target.addContractsImplemented(target.externalContractsImplemented()); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoCriteriaBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoCriteriaBlueprint.java deleted file mode 100644 index 34b8f630231..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoCriteriaBlueprint.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Criteria to discover services. - * - * @see Services - * @see ServiceInfo - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -@Prototype.CustomMethods(ServiceInfoCriteriaBlueprint.CustomMethods.class) -interface ServiceInfoCriteriaBlueprint { - - /** - * The managed service implementation type name. - * - * @return the service type name - */ - Optional serviceTypeName(); - - /** - * The managed service assigned Scope's. - * - * @return the service scope type name - */ - @Option.Singular - Set scopeTypeNames(); - - /** - * The managed service assigned Qualifier's. - * - * @return the service qualifiers - */ - @Option.Singular - Set qualifiers(); - - /** - * The managed services advertised types (i.e., typically its interfaces). - * - * @see ExternalContracts - * @return the service contracts implemented - */ - @Option.Singular("contractImplemented") - Set contractsImplemented(); - - /** - * The optional {@link RunLevel} ascribed to the service. - * - * @return the service's run level - */ - Optional runLevel(); - - /** - * Weight that was declared on the type itself. - * - * @return the declared weight - */ - Optional weight(); - - /** - * The managed services external contracts / interfaces. These should also be contained within - * {@link #contractsImplemented()}. External contracts are from other modules other than the module containing - * the implementation typically. - * - * @see ExternalContracts - * @return the service external contracts implemented - */ - @Option.Singular("externalContractImplemented") - Set externalContractsImplemented(); - - /** - * The management agent (i.e., the activator) that is responsible for creating and activating - typically build-time created. - * - * @return the activator type name - */ - Optional activatorTypeName(); - - /** - * The name of the ascribed module, if known. - * - * @return the module name - */ - Optional moduleName(); - - /** - * Determines whether the non-proxied, {@link Intercepted} services should be returned in any lookup operation. If this - * option is disabled then only the {@link Interceptor}-generated service will be eligible to be returned and not the service - * being intercepted. - * The default value is {@code false}. - * - * @return true if the non-proxied type intercepted services should be eligible - */ - @ConfiguredOption("false") - boolean includeIntercepted(); - - /** - * Determines whether this service info matches the criteria for injection. - * Matches is a looser form of equality check than {@code equals()}. If a service matches criteria - * it is generally assumed to be viable for assignability. - * - * @param criteria the criteria to compare against - * @return true if the criteria provided matches this instance - */ - // internal note: it is unfortunate that we have a matches() here as well as in ServiceInfo. This is what happened - // when we split ServiceInfo into ServiceInfoCriteria. Sometimes we need ServiceInfo.matches(criteria), and other times - // ServiceInfoCriteria.matches(criteria). - default boolean matches(ServiceInfoCriteriaBlueprint criteria) { - return matchesContracts(criteria) - && scopeTypeNames().containsAll(criteria.scopeTypeNames()) - && Qualifiers.matchesQualifiers(qualifiers(), criteria.qualifiers()) - && matches(activatorTypeName(), criteria.activatorTypeName()) - && matches(runLevel(), criteria.runLevel()) - // && matchesWeight(this, criteria) -- intentionally not checking weight here! - && matches(moduleName(), criteria.moduleName()); - } - - /** - * Determines whether the provided criteria match just the contracts portion of the provided criteria. Note that - * it is expected any external contracts have been consolidated into the regular contract section. - * - * @param criteria the criteria to compare against - * @return true if the criteria provided matches this instance from only the contracts point of view - */ - default boolean matchesContracts(ServiceInfoCriteriaBlueprint criteria) { - if (criteria == InjectionServices.EMPTY_CRITERIA) { - return true; - } - - boolean matches = matches(serviceTypeName(), criteria.serviceTypeName()); - if (matches && criteria.serviceTypeName().isEmpty()) { - matches = contractsImplemented().containsAll(criteria.contractsImplemented()); - } - return matches; - } - - private static boolean matches(Object src, - Optional criteria) { - - return criteria.map(o -> Objects.equals(src, o)).orElse(true); - - } - - final class CustomMethods { - private CustomMethods() { - } - - /** - * The managed services advertised types (i.e., typically its interfaces). - * - * @param builder builder instance - * @param contract the service contracts implemented - * @see #contractsImplemented() - */ - @Prototype.BuilderMethod - static void addContractImplemented(ServiceInfoCriteria.BuilderBase builder, Class contract) { - builder.addContractImplemented(TypeName.create(contract)); - } - } -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceInjectionPlanBinder.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceInjectionPlanBinder.java deleted file mode 100644 index 0c52f845591..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceInjectionPlanBinder.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Responsible for registering the injection plan to the services in the service registry. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ServiceInjectionPlanBinder { - - /** - * Bind an injection plan to a service provider instance. - * - * @param serviceProvider the service provider to receive the injection plan. - * @return the binder to use for binding the injection plan to the service provider - */ - Binder bindTo(ServiceProvider serviceProvider); - - - /** - * The binder builder for the service plan. - * - * @see InjectionPointInfo - */ - interface Binder { - - /** - * Binds a single service provider to the injection point identified by {@link InjectionPointInfo#id()}. - * It is assumed that the caller of this is aware of the proper cardinality for each injection point. - * - * @param id the injection point identity - * @param serviceProvider the service provider to bind to this identity. - * @return the binder builder - */ - Binder bind(String id, - ServiceProvider serviceProvider); - - /** - * Binds a list of service providers to the injection point identified by {@link InjectionPointInfo#id()}. - * It is assumed that the caller of this is aware of the proper cardinality for each injection point. - * - * @param id the injection point identity - * @param serviceProviders the list of service providers to bind to this identity - * @return the binder builder - */ - Binder bindMany(String id, - ServiceProvider... serviceProviders); - - /** - * Represents a void / null bind, only applicable for an Optional injection point. - * - * @param id the injection point identity - * @return the binder builder - */ - Binder bindVoid(String id); - - /** - * Represents injection points that cannot be bound at startup, and instead must rely on a - * deferred resolver based binding. Typically, this represents some form of dynamic or configurable instance. - * - * @param id the injection point identity - * @param serviceType the service type needing to be resolved - * @return the binder builder - */ - Binder resolvedBind(String id, - Class serviceType); - - /** - * Commits the bindings for this service provider. - */ - void commit(); - - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceProvider.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceProvider.java deleted file mode 100644 index 5402a5b20ce..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceProvider.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -import io.helidon.common.Weighted; - -import jakarta.inject.Singleton; - -/** - * Provides management lifecycle around services. - * - * @param the type that this service provider manages - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ServiceProvider extends InjectionPointProvider, Weighted { - - /** - * Identifies the service provider physically and uniquely. - * - * @return the unique identity of the service provider - */ - String id(); - - /** - * Describe the service provider. This will change based upon activation state. - * - * @return the logical and immutable description - */ - String description(); - - /** - * Does the service provide singletons, does it always produce the same result for every call to {@link #get()}. - * I.e., if the managed service implements Provider or - * {@link InjectionPointProvider} then this typically is considered not a singleton provider. - * I.e., If the managed services is NOT {@link Singleton}, then it will be treated as per request / dependent - * scope. - * Note that this is similar in nature to RequestScope, except the "official" request scope is bound to the - * web request. Here, we are speaking about contextually any caller asking for a new instance of the service in - * question. The requester in question will ideally be able to identify itself to this provider via - * {@link InjectionPointProvider#first(ContextualServiceQuery)} so that this provider can properly - * service the "provide" request. - * - * @return true if the service provider provides per-request instances for each caller - */ - boolean isProvider(); - - /** - * The meta information that describes the service. Must remain immutable for the lifetime of the JVM post - * binding - ie., after {@link ServiceBinder#bind(ServiceProvider)} is called. - * - * @return the meta information describing the service - */ - ServiceInfo serviceInfo(); - - /** - * Provides the dependencies for this service provider if known, or null if not known or not available. - * - * @return the dependencies this service provider has or null if unknown or unavailable - */ - DependenciesInfo dependencies(); - - /** - * The current activation phase for this service provider. - * - * @return the activation phase - */ - Phase currentActivationPhase(); - - /** - * The agent responsible for activation - this will be non-null for build-time activators. If not present then - * an {@link Injector} must be used to reflectively activate. - * - * @return the activator - */ - Optional activator(); - - /** - * The agent responsible for deactivation - this will be non-null for build-time activators. If not present then - * an {@link Injector} must be used to reflectively deactivate. - * - * @return the deactivator to use or null if the service is not interested in deactivation - */ - Optional deActivator(); - - /** - * The optional method handling PreDestroy. - * - * @return the post-construct method or empty if there is none - */ - Optional postConstructMethod(); - - /** - * The optional method handling PostConstruct. - * - * @return the pre-destroy method or empty if there is none - */ - Optional preDestroyMethod(); - - /** - * The agent/instance to be used for binding this service provider to the injectable application that was code generated. - * - * @return the service provider that should be used for binding, or empty if this provider does not support binding - * @see ModuleComponent - * @see ServiceBinder - * @see ServiceProviderBindable - */ - Optional> serviceProviderBindable(); - - /** - * The type of the service being managed. - * - * @return the service type being managed - */ - Class serviceType(); -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderBindable.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderBindable.java deleted file mode 100644 index 521767af816..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderBindable.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Optional; - -/** - * An extension to {@link ServiceProvider} that allows for startup binding from a {@code Injection$$Application}, - * and thereby works in conjunction with the {@link ServiceBinder} during injection service registry - * initialization. - *

- * The only guarantee the provider implementation has is ensuring that {@link ModuleComponent} instances - * are bound to the Services instances, as well as informed on the module name. - *

- * Generally this class should be called internally by the framework, and typically occurs only during initialization sequences. - * - * @param the type that this service provider manages - * @see Application - * @see ServiceProvider#serviceProviderBindable() - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ServiceProviderBindable extends ServiceProvider { - - /** - * Called to inform a service provider the module name it is bound to. Will only be called when there is a non-null - * module name associated for the given {@link ModuleComponent}. A service provider can be associated with - * 0..1 modules. - * - * @param moduleName the non-null module name - */ - void moduleName(String moduleName); - - /** - * Returns true if this service provider instance is an {@link Interceptor}. - * - * @return true if this service provider is an interceptor - */ - default boolean isInterceptor() { - return false; - } - - /** - * Returns {@code true} if this service provider is intercepted. - * - * @return flag indicating whether this service provider is intercepted - */ - default boolean isIntercepted() { - return interceptor().isPresent(); - } - - /** - * Returns the service provider that intercepts this provider. - * - * @return the service provider that intercepts this provider - */ - Optional> interceptor(); - - /** - * Sets the interceptor for this service provider. - * - * @param interceptor the interceptor for this provider - */ - default void interceptor(ServiceProvider interceptor) { - // NOP; intended to be overridden if applicable - throw new UnsupportedOperationException(); - } - - /** - * Gets the root/parent provider for this service. A root/parent provider is intended to manage it's underlying - * providers. Note that "root" and "parent" are interchangeable here since there is at most one level of depth that occurs - * when {@link ServiceProvider}'s are wrapped by other providers. - * - * @return the root/parent provider or empty if this instance is the root provider - */ - default Optional> rootProvider() { - return Optional.empty(); - } - - /** - * Returns true if this provider is the root provider. - * - * @return indicates whether this provider is a root provider - the default is true - */ - default boolean isRootProvider() { - return rootProvider().isEmpty(); - } - - /** - * Sets the root/parent provider for this instance. - * - * @param rootProvider sets the root provider - */ - default void rootProvider(ServiceProvider rootProvider) { - // NOP; intended to be overridden if applicable - throw new UnsupportedOperationException(); - } - - /** - * Returns the previously assigned {@link InjectionServices} instance. - * - * @return the previously assigned injection services instance, or empty if never assigned - * - * @see #injectionServices(Optional) - */ - Optional injectionServices(); - - /** - * Assigns the services instance this provider is bound to. A service provider can be associated with 0..1 services instance. - * If not set, the service provider should use {@link InjectionServices#injectionServices()} to ascertain the instance. - * - * @param injectionServices the injection services instance, or empty to clear any active binding - */ - void injectionServices(Optional injectionServices); - - /** - * The binder can be provided by the service provider to deterministically set the injection plan at compile-time, and - * subsequently loaded at early startup initialization. - * - * @return binder used for this service provider, or empty if not capable or ineligible of being bound - */ - default Optional injectionPlanBinder() { - return Optional.empty(); - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderInjectionException.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderInjectionException.java deleted file mode 100644 index c61c48144b2..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderInjectionException.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.Objects; -import java.util.Optional; - -/** - * Represents an injection exception. These might be thrown either at compile time or at runtime depending upon how the - * application is built. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class ServiceProviderInjectionException extends InjectionServiceProviderException { - - /** - * The optional activation log (configure to enabled). - * - * @see InjectionServicesConfig#activationLogs() - */ - private ActivationLog activationLog; - - /** - * Injection, or a required service lookup related exception. - * - * @param msg the message - */ - public ServiceProviderInjectionException(String msg) { - super(msg); - } - - /** - * Injection, or a required service lookup related exception. - * - * @param msg the message - * @param cause the root cause - * @param serviceProvider the service provider - */ - public ServiceProviderInjectionException(String msg, - Throwable cause, - ServiceProvider serviceProvider) { - super(msg, cause, serviceProvider); - } - - /** - * Injection, or a required service lookup related exception. - * - * @param msg the message - * @param serviceProvider the service provider - */ - public ServiceProviderInjectionException(String msg, - ServiceProvider serviceProvider) { - super(msg, serviceProvider); - } - - /** - * Returns the activation log if available. - * - * @return the optional activation log - */ - public Optional activationLog() { - return Optional.ofNullable(activationLog); - } - - /** - * Sets the activation log on this exception instance. - * - * @param log the activation log - * @return this exception instance - */ - public ServiceProviderInjectionException activationLog(ActivationLog log) { - this.activationLog = Objects.requireNonNull(log); - return this; - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderProvider.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderProvider.java deleted file mode 100644 index 2870414010f..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceProviderProvider.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.List; -import java.util.Map; - -/** - * Instances of these provide lists and maps of {@link ServiceProvider}s. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ServiceProviderProvider { - - /** - * Returns a list of all matching service providers, potentially including itself in the result. - * - * @param criteria the injection point criteria that must match - * @param wantThis if this instance matches criteria, do we want to return this instance as part of the result - * @param thisAlreadyMatches an optimization that signals to the implementation that this instance has already - * matched using the standard service info matching checks - * @return the list of service providers matching - */ - List> serviceProviders(ServiceInfoCriteria criteria, - boolean wantThis, - boolean thisAlreadyMatches); - - /** - * This method will only apply to the managed/slave instances being provided, not to itself as in the case for - * {@link #serviceProviders(ServiceInfoCriteria, boolean, boolean)}. - * - * @param criteria the injection point criteria that must match - * @return the map of managed service providers matching the criteria, identified by its key/context - */ - Map> managedServiceProviders(ServiceInfoCriteria criteria); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Services.java b/inject/api/src/main/java/io/helidon/inject/api/Services.java deleted file mode 100644 index bef170287a4..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Services.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.List; -import java.util.Optional; - -import io.helidon.common.types.TypeName; - -/** - * The service registry. The service registry generally has knowledge about all the services that are available within your - * application, along with the contracts (i.e., interfaces) they advertise, the qualifiers that optionally describe them, and oll - * of each services' dependencies on other service contracts, etc. - *

- * Collectively these service instances are considered "the managed service instances" under Injection. A {@link ServiceProvider} - * wrapper - * provides lifecycle management on the underlying service instances that each provider "manages" in terms of activation, scoping, - * etc. The service providers are typically created during compile-time processing when the Injection APT processor is applied to your - * module (i.e., any service annotated using {@link jakarta.inject.Singleton}, - * {@link Contract}, {@link jakarta.inject.Inject}, etc.) during compile time. Additionally, they can be built - * using the Injection maven-plugin. Note also that the maven-plugin can be used to "compute" your applications entire DI model - * at compile time, generating an {@link Application} class that will be used at startup when found by the - * Injection framework. - *

- * This Services interface exposes a read-only set of methods providing access to these "managed service" providers, and available - * via one of the lookup methods provided. Once you resolve the service provider(s), the service provider can be activated by - * calling one of its get() methods. This is equivalent to the declarative form just using {@link jakarta.inject.Inject} instead. - * Note that activation of a service might result in activation chaining. For example, service A injects service B, etc. When - * service A is activated then service A's dependencies (i.e., injection points) need to be activated as well. To avoid long - * activation chaining, it is recommended to that users strive to use {@link jakarta.inject.Provider} injection whenever possible. - * Provider injection (a) breaks long activation chains from occurring by deferring activation until when those services are - * really - * needed, and (b) breaks circular references that lead to {@link ServiceProviderInjectionException} during activation (i.e., - * service A injects B, and service B injects A). - *

- * The services are ranked according to the provider's comparator. The Injection framework will rank according to a strategy that - * first looks for - * {@link io.helidon.common.Weighted}, then {@link jakarta.annotation.Priority}, and finally by the alphabetic ordering according - * to the type name (package and class canonical name). - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface Services { - - /** - * Retrieve the "first" service that implements a given contract type with the expectation that there is a match available. - * - * @param type the type to find - * @param the type of the service - * @return the best service provider matching the criteria - * @throws InjectionException if resolution fails to resolve a match - */ - default ServiceProvider lookup(Class type) { - return lookupFirst(type, true) - .orElseThrow(() -> new InjectionException("There are no service providers for service of type " + type.getName())); - } - - /** - * Retrieve the "first" named service that implements a given contract type with the expectation that there is a match - * available. - * - * @param type the type criteria to find - * @param name the name for the service - * @param the type of the service - * @return the best service provider matching the criteria - * @throws InjectionException if resolution fails to resolve a match - */ - default ServiceProvider lookup(Class type, - String name) { - return lookupFirst(type, name, true) - .orElseThrow(() -> new InjectionException("There are no service providers for service of type " + type.getName())); - } - - /** - * Retrieve the "first" service that implements a given contract type with no expectation that there is a match available - * unless {@code expected = true}. - * - * @param type the type criteria to find - * @param expected indicates whether the provider should throw if a match is not found - * @param the type of the service - * @return the best service provider matching the criteria, or {@code empty} if (@code expected = false) and no match found - * @throws InjectionException if expected=true and resolution fails to resolve a match - */ - Optional> lookupFirst(Class type, - boolean expected); - - /** - * Retrieve the "first" service that implements a given contract type with no expectation that there is a match available - * unless {@code expected = true}. - * - * @param type the type criteria to find - * @param name the name for the service - * @param expected indicates whether the provider should throw if a match is not found - * @param the type of the service - * @return the best service provider matching the criteria, or {@code empty} if (@code expected = false) and no match found - * @throws InjectionException if expected=true and resolution fails to resolve a match - */ - Optional> lookupFirst(Class type, - String name, - boolean expected); - - /** - * Retrieves the first match based upon the passed service info criteria. - * - * @param criteria the criteria to find - * @return the best service provider - * @throws InjectionException if resolution fails to resolve a match - */ - default ServiceProvider lookup(ServiceInfoCriteria criteria) { - return lookupFirst(criteria, true).orElseThrow(); - } - - /** - * Retrieves the first match based upon the passed service info criteria. - * - * @param criteria the criteria to find - * @param expected indicates whether the provider should throw if a match is not found - * @return the best service provider matching the criteria, or {@code empty} if (@code expected = false) and no match found - * @throws InjectionException if expected=true and resolution fails to resolve a match - */ - Optional> lookupFirst(ServiceInfoCriteria criteria, - boolean expected); - - /** - * Retrieves the first match based upon the passed service info criteria. - * - * @param contract contract that must be implemented - * @param criteria the criteria to find - * @param expected indicates whether the provider should throw if a match is not found - * @return the best service provider matching the criteria, or {@code empty} if (@code expected = false) and no match found - * @throws InjectionException if expected=true and resolution fails to resolve a match - * @param type of the service - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - default Optional> lookupFirst(Class contract, ServiceInfoCriteria criteria, boolean expected) { - return (Optional) lookupFirst(ServiceInfoCriteria.builder(criteria) - .addContractImplemented(TypeName.create(contract)) - .build(), - expected); - } - - /** - * Retrieves the first match based upon the passed service info criteria. - *

- * This is the same as calling the following: - *

-     *     lookupFirst(criteria, true).orElseThrow();
-     * 
- * - * @param criteria the criteria to find - * @return the best service provider matching the criteria - * @throws InjectionException if resolution fails to resolve a match - */ - default ServiceProvider lookupFirst(ServiceInfoCriteria criteria) { - return lookupFirst(criteria, true).orElseThrow(); - } - - /** - * Retrieves the first match based upon the passed service info criteria. - *

- * This is the same as calling the following: - *

-     *     lookupFirst(criteria, true).orElseThrow();
-     * 
- * - * @param type the type criteria to find - * @param the type of the service - * @return the best service provider matching the criteria - * @throws InjectionException if resolution fails to resolve a match - */ - default ServiceProvider lookupFirst(Class type) { - return lookupFirst(type, true).orElseThrow(); - } - - /** - * Retrieve all services that implement a given contract type. - * - * @param type the type criteria to find - * @param the type of the service being managed - * @return the list of service providers matching criteria - */ - List> lookupAll(Class type); - - /** - * Retrieve all services that match the criteria. - * - * @param criteria the criteria to find - * @return the list of service providers matching criteria - */ - default List> lookupAll(ServiceInfoCriteria criteria) { - return lookupAll(criteria, false); - } - - /** - * Lookup all services that match the criteria and share a given contract type. - * - * @param type the type criteria to find - * @param criteria additional criteria - * @return list of service providers matching criteria - * @param type of the service being managed - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - default List> lookupAll(Class type, ServiceInfoCriteria criteria) { - return (List) lookupAll(ServiceInfoCriteria.builder(criteria) - .addContractImplemented(TypeName.create(type)) - .build()); - } - - /** - * Retrieve all services that match the criteria. - * - * @param criteria the criteria to find - * @param expected indicates whether the provider should throw if a match is not found - * @return the list of service providers matching criteria - */ - List> lookupAll(ServiceInfoCriteria criteria, - boolean expected); - - /** - * Implementors can provide a means to use a "special" services registry that better applies to the target injection - * point context to apply for sub-lookup* operations. If the provider does not support contextual lookup then the same - * services instance as this will be returned. - * - * @param ctx the injection point context to use to filter the services to what qualifies for this injection point - * @return the qualifying services relative to the given context - * @see InjectionServicesConfig#supportsContextualLookup() - */ - default Services contextualServices(InjectionPointInfo ctx) { - return this; - } - -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/Startable.java b/inject/api/src/main/java/io/helidon/inject/api/Startable.java deleted file mode 100644 index 991028054e6..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/Startable.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -/** - * Some components may require start when Helidon is bootstrapped, such as WebServer (to open server sockets). - * This interface is a Helidon Injection contract, that allows us to discover all startable services and start them - * on boot when desired. - *

- * This contract should be used for cases where the construction of the object (using constructor, and maybe - * {@link jakarta.annotation.PostConstruct} - where we create a fully configured instance) is different from its start - * transition (such as opening sockets, connecting to remote messaging queues, streams, topics, etc.). - * - * @see Helidon#start() - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface Startable { - /** - * Start this service. - */ - void startService(); -} diff --git a/inject/api/src/main/java/io/helidon/inject/api/package-info.java b/inject/api/src/main/java/io/helidon/inject/api/package-info.java deleted file mode 100644 index 0d270d1b120..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/api/package-info.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The Helidon Injection API provide these annotation types that are typically used at compile time - * to assign special meaning to the type. It is used in conjunction with Helidon tooling (see the {@code injection processor} and - * injectio {@code maven-plugin} modules) to create and validate the DI module at compile time. - *

    - *
  • {@link io.helidon.inject.api.Contract} - signifies that the type can be used for lookup in the service registry.
  • - *
  • {@link io.helidon.inject.api.ExternalContracts} - same as Contract, but applied to the implementation class instead.
  • - *
  • {@link io.helidon.inject.api.RunLevel} - ascribes meaning for when the service should start.
  • - *
- * Also note that the set of annotations from both the {@code jakarta.inject} and {@code jakarta.annotation} modules are the - * primary way to annotate your DI model types. - *

- * Other types from the API are less commonly used, but are still made available for situations where programmatic access - * is required or desirable in some way. The two most common types for entry into this part of the API are shown below. - *

    - *
  • {@link io.helidon.inject.api.InjectionServices} - suite of services that are typically delivered by the Injection provider.
  • - *
  • {@link io.helidon.inject.api.Services} - the services registry, which is one such service from this suite.
  • - *
- * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -package io.helidon.inject.api; diff --git a/inject/api/src/main/java/io/helidon/inject/spi/InjectionPlanBlueprint.java b/inject/api/src/main/java/io/helidon/inject/spi/InjectionPlanBlueprint.java deleted file mode 100644 index 6c949ee3caa..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/spi/InjectionPlanBlueprint.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.spi; - -import java.util.List; -import java.util.Optional; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.inject.api.ServiceProvider; - -/** - * Represents the injection plan targeting a given {@link io.helidon.inject.api.ServiceProvider}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Prototype.Blueprint -interface InjectionPlanBlueprint { - - /** - * The service provider this plan pertains to. - * - * @return the service provider this plan pertains to - */ - ServiceProvider serviceProvider(); - - /** - * The injection point info for this element, which will also include its identity information. - * - * @return the injection point info for this element - */ - io.helidon.inject.api.InjectionPointInfo injectionPointInfo(); - - /** - * The list of service providers that are qualified to satisfy the given injection point for this service provider. - * - * @return the qualified service providers for this injection point - */ - @Option.Singular - List> injectionPointQualifiedServiceProviders(); - - /** - * Flag indicating whether resolution occurred. - * - * @return true if resolution occurred - */ - @ConfiguredOption("false") - boolean wasResolved(); - - /** - * The resolved value, set only if {@link #wasResolved()}. - * - * @return any resolved value - */ - Optional resolved(); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/spi/InjectionResolver.java b/inject/api/src/main/java/io/helidon/inject/spi/InjectionResolver.java deleted file mode 100644 index b0afd7eadf1..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/spi/InjectionResolver.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.spi; - -import java.util.Optional; - -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ServiceProvider; - -/** - * Implementors of this contract can assist with resolving injection points. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface InjectionResolver { - - /** - * Attempts to resolve the injection point info for a given service provider. - *

- * There are two modes that injection resolvers run through. - * Phase 1 (resolveIps=false) is during the time when the injection plan is being formulated. This is the time we need - * to identify which {@link ServiceProvider} instances qualify. - * Phase 2 (resolveIps=true) is during actual resolution, and typically comes during the service activation lifecycle. - * - * @param ipInfo the injection point being resolved - * @param injectionServices the services registry - * @param serviceProvider the service provider this pertains to - * @param resolveIps flag indicating whether injection points should be resolved - * @return the resolution for the plan or the injection point, or empty if unable to resolve the injection point context - */ - Optional resolve(InjectionPointInfo ipInfo, - InjectionServices injectionServices, - ServiceProvider serviceProvider, - boolean resolveIps); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/spi/InjectionServicesProvider.java b/inject/api/src/main/java/io/helidon/inject/spi/InjectionServicesProvider.java deleted file mode 100644 index 1ec4ac61230..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/spi/InjectionServicesProvider.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.spi; - -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; - -/** - * Java {@link java.util.ServiceLoader} provider interface to find implementation of {@link InjectionServices}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface InjectionServicesProvider { - - /** - * Provide the {@code Injection} Services implementation given the provided primordial {@link Bootstrap} - * configuration instance. - * - * @param bootstrap the primordial bootstrap configuration - * @return services instance configured with the provided bootstrap instance - */ - InjectionServices services(Bootstrap bootstrap); - -} diff --git a/inject/api/src/main/java/io/helidon/inject/spi/package-info.java b/inject/api/src/main/java/io/helidon/inject/spi/package-info.java deleted file mode 100644 index b34020cf86d..00000000000 --- a/inject/api/src/main/java/io/helidon/inject/spi/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection SPI. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -package io.helidon.inject.spi; diff --git a/inject/api/src/main/java/module-info.java b/inject/api/src/main/java/module-info.java deleted file mode 100644 index 18b37f0c224..00000000000 --- a/inject/api/src/main/java/module-info.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection API module. - * - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.api { - - requires io.helidon.common.config; - requires io.helidon.common.types; - requires io.helidon.common; - requires io.helidon.logging.common; - - requires jakarta.inject; - - requires static io.helidon.config.metadata; - requires static jakarta.annotation; - - requires transitive io.helidon.builder.api; - - exports io.helidon.inject.api; - exports io.helidon.inject.spi; - - uses io.helidon.inject.spi.InjectionServicesProvider; - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/InjectionServicesTest.java b/inject/api/src/test/java/io/helidon/inject/api/InjectionServicesTest.java deleted file mode 100644 index 8f876bf8c95..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/InjectionServicesTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import io.helidon.inject.api.testsubjects.InjectionServices2; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.sameInstance; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * Injection services tests. - */ -class InjectionServicesTest { - - @BeforeEach - @AfterEach - void reset() { - InjectionServicesHolder.reset(); - } - - /** - * Test basic loader. - */ - @Test - void testGetInjectionServices() { - assertThat(InjectionServices.globalBootstrap(), optionalEmpty()); - Bootstrap bootstrap = Bootstrap.builder().build(); - InjectionServices.globalBootstrap(bootstrap); - assertThat(InjectionServices.globalBootstrap().orElseThrow(), sameInstance(bootstrap)); - - IllegalStateException e = assertThrows(IllegalStateException.class, () -> InjectionServices.globalBootstrap(bootstrap)); - assertThat(e.getMessage(), - equalTo("The bootstrap has already been set - " - + "use the (-D and/or -A) tag 'inject.debug=true' to see full trace output.")); - - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - assertThat(injectionServices, notNullValue()); - assertThat(injectionServices, instanceOf(InjectionServices2.class)); - assertThat(injectionServices, sameInstance(InjectionServices.injectionServices().orElseThrow())); - - assertThat(injectionServices.bootstrap(), sameInstance(bootstrap)); - } - - @Test - void unrealizedServices() { - assertThat(InjectionServices.unrealizedServices(), optionalEmpty()); - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/PriorityAndServiceTypeComparatorTest.java b/inject/api/src/test/java/io/helidon/inject/api/PriorityAndServiceTypeComparatorTest.java deleted file mode 100644 index b1451733f4b..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/PriorityAndServiceTypeComparatorTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -import io.helidon.common.Weighted; -import io.helidon.common.Weights; -import io.helidon.inject.api.testsubjects.InjectionServices2Provider; -import io.helidon.inject.api.testsubjects.InjectionServices3Provider; -import io.helidon.inject.api.testsubjects.InjectionServices1Provider; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.lessThan; - -/** - * Ensure the weights comparator from common works the way we expect it to. Sanity test for Injection. - */ -class PriorityAndServiceTypeComparatorTest { - - static final Comparator comparator = Weights.weightComparator(); - - @Test - void ordering() { - assertThat(comparator.compare(null, null), is(0)); - assertThat(comparator.compare(null, null), is(0)); - assertThat(comparator.compare("a", "a"), is(0)); - assertThat(comparator.compare("a", "b"), is(lessThan(0))); - assertThat(comparator.compare("b", "a"), is(greaterThan(0))); - assertThat(comparator.compare(1, 2), is(lessThan(0))); - - assertThat(comparator.compare(new HighWeight(), new HighWeight()), is(0)); - assertThat(comparator.compare(new LowWeight(), new HighWeight()), is(greaterThan(0))); - assertThat(comparator.compare(new LowWeight(), new DefaultWeight()), is(greaterThan(0))); - assertThat(comparator.compare(new DefaultWeight(), new LowWeight()), is(lessThan(0))); - assertThat(comparator.compare(new DefaultWeight(), null), is(lessThan(0))); - assertThat(comparator.compare(null, new DefaultWeight()), is(greaterThan(0))); - assertThat(comparator.compare(new NoWeight(), null), is(lessThan(0))); - assertThat(comparator.compare(null, new NoWeight()), is(greaterThan(0))); - - assertThat(comparator.compare(new DefaultWeight(), new DefaultWeight()), is(0)); - assertThat(comparator.compare(new DefaultWeight(), new NoWeight()), lessThan(0)); - assertThat(comparator.compare(new NoWeight(), new NoWeight()), is(0)); - assertThat(comparator.compare(new NoWeight(), new DefaultWeight()), is(greaterThan(0))); - - assertThat(comparator.compare(new JustAClass(), new JustBClass()), is(lessThan(0))); - assertThat(comparator.compare(new JustBClass(), new JustAClass()), is(greaterThan(0))); - assertThat(comparator.compare(new JustBClass(), new DefaultWeight()), is(greaterThan(0))); - assertThat(comparator.compare(new DefaultWeight(), new JustAClass()), is(lessThan(0))); - assertThat(comparator.compare(null, new JustAClass()), is(greaterThan(0))); - assertThat(comparator.compare(new JustAClass(), null), is(lessThan(0))); - - var list = new ArrayList<>(List.of(new InjectionServices1Provider(), - new InjectionServices2Provider(), - new InjectionServices3Provider())); - list.sort(comparator); - assertThat(list.get(0), instanceOf(InjectionServices2Provider.class)); - assertThat(list.get(1), instanceOf(InjectionServices3Provider.class)); - assertThat(list.get(2), instanceOf(InjectionServices1Provider.class)); - } - - static class DefaultWeight implements Weighted { - } - - static class NoWeight implements Weighted { - public Integer getPriority() { - return null; - } - } - - static class LowWeight implements Weighted { - public Integer getPriority() { - return 1; - } - } - - static class HighWeight implements Weighted { - @Override - public double weight() { - return DEFAULT_WEIGHT + 10; - } - } - - static class JustAClass { - } - - static class JustBClass { - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/QualifierTest.java b/inject/api/src/test/java/io/helidon/inject/api/QualifierTest.java deleted file mode 100644 index 834e6285ac7..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/QualifierTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import io.helidon.common.types.Annotation; - -import jakarta.inject.Named; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -class QualifierTest { - - @Test - void buildAndCompare() { - Qualifier qav1 = Qualifier.builder() - .type(Named.class) - .value("x.y") - .build(); - Annotation qav2 = Qualifier.builder() - .type(Named.class) - .value("x.y") - .build(); - assertThat(qav1.compareTo(qav2), - is(0)); - } - - @Named("io.helidon.inject.api.DefaultQualifierTest") - @ClassNamed(QualifierTest.class) - @Test - public void createClassNamed() throws Exception { - Qualifier qav1 = Qualifier.createNamed(QualifierTest.class); - Qualifier qav2 = Qualifier.builder() - .type(Named.class) - .value(Qualifier.class.getName()) - .build(); - assertThat(qav1.compareTo(qav2), - is(0)); - - assertThat("runtime retention expected for " + ClassNamed.class, - getClass().getMethod("createClassNamed").getAnnotation(ClassNamed.class), - notNullValue()); - - } - - @Test - public void buildAndCompareClassNamed() { - Qualifier qav1 = Qualifier.createNamed(new FakeNamed()); - Qualifier qav2 = Qualifier.createNamed(new FakeClassNamed()); - - assertThat(qav1.compareTo(qav2), - is(0)); - assertThat(qav2.compareTo(qav1), - is(0)); - } - - static class FakeNamed implements Named { - @Override - public String value() { - return QualifierTest.class.getName(); - } - - @Override - public Class annotationType() { - return Named.class; - } - } - - static class FakeClassNamed implements ClassNamed { - @Override - public Class value() { - return QualifierTest.class; - } - - @Override - public Class annotationType() { - return ClassNamed.class; - } - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/AbstractInjectionServices.java b/inject/api/src/test/java/io/helidon/inject/api/testsubjects/AbstractInjectionServices.java deleted file mode 100644 index 6c527bbacc3..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/AbstractInjectionServices.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api.testsubjects; - -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ActivationLog; -import io.helidon.inject.api.ActivationResult; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Injector; -import io.helidon.inject.api.Metrics; -import io.helidon.inject.api.InjectionServicesConfig; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.Services; - -abstract class AbstractInjectionServices implements InjectionServices { - - @Override - public InjectionServicesConfig config() { - return null; - } - - @Override - public Optional services(boolean initialize) { - return Optional.empty(); - } - - @Override - public Services services() { - return null; - } - - @Override - public Optional injector() { - return Optional.empty(); - } - - @Override - public Optional> shutdown() { - return Optional.empty(); - } - - @Override - public Optional activationLog() { - return Optional.empty(); - } - - @Override - public Optional metrics() { - return Optional.empty(); - } - - @Override - public Optional> lookups() { - return Optional.empty(); - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices1.java b/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices1.java deleted file mode 100644 index 2bcbabf7753..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices1.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api.testsubjects; - -import java.util.Objects; - -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServicesConfig; - -class InjectionServices1 extends AbstractInjectionServices { - private final Bootstrap bootstrap; - - InjectionServices1(Bootstrap bootstrap) { - this.bootstrap = Objects.requireNonNull(bootstrap); - } - - @Override - public Bootstrap bootstrap() { - return bootstrap; - } - - @Override - public InjectionServicesConfig config() { - return null; - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices1Provider.java b/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices1Provider.java deleted file mode 100644 index 0a95f3c8a5a..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices1Provider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api.testsubjects; - -import io.helidon.common.Weight; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.spi.InjectionServicesProvider; - -@Weight(1) -public class InjectionServices1Provider implements InjectionServicesProvider { - - @Override - public InjectionServices services(Bootstrap bootstrap) { - return new InjectionServices1(bootstrap); - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices2.java b/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices2.java deleted file mode 100644 index daa5ff6a78f..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices2.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api.testsubjects; - -import java.util.Objects; - -import io.helidon.inject.api.Bootstrap; - -public class InjectionServices2 extends AbstractInjectionServices { - private final Bootstrap bootstrap; - - InjectionServices2(Bootstrap bootstrap) { - this.bootstrap = Objects.requireNonNull(bootstrap); - } - - @Override - public Bootstrap bootstrap() { - return bootstrap; - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices2Provider.java b/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices2Provider.java deleted file mode 100644 index aa6cdaeea3d..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices2Provider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api.testsubjects; - -import io.helidon.common.Weight; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.spi.InjectionServicesProvider; - -@Weight(20) -public class InjectionServices2Provider implements InjectionServicesProvider { - - @Override - public InjectionServices services(Bootstrap bootstrap) { - return new InjectionServices2(bootstrap); - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices3.java b/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices3.java deleted file mode 100644 index 3f163af453e..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices3.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api.testsubjects; - -import java.util.Objects; - -import io.helidon.inject.api.Bootstrap; - -class InjectionServices3 extends AbstractInjectionServices { - private final Bootstrap bootstrap; - - InjectionServices3(Bootstrap bootstrap) { - this.bootstrap = Objects.requireNonNull(bootstrap); - } - - @Override - public Bootstrap bootstrap() { - return bootstrap; - } - -} diff --git a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices3Provider.java b/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices3Provider.java deleted file mode 100644 index 629a32d4eca..00000000000 --- a/inject/api/src/test/java/io/helidon/inject/api/testsubjects/InjectionServices3Provider.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api.testsubjects; - -import io.helidon.common.Weight; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.spi.InjectionServicesProvider; - -@Weight(3) -public class InjectionServices3Provider implements InjectionServicesProvider { - - @Override - public InjectionServices services(Bootstrap bootstrap) { - return new InjectionServices3(bootstrap); - } - -} diff --git a/inject/api/src/test/resources/META-INF/services/io.helidon.inject.spi.InjectionServicesProvider b/inject/api/src/test/resources/META-INF/services/io.helidon.inject.spi.InjectionServicesProvider deleted file mode 100644 index a5f0fde425e..00000000000 --- a/inject/api/src/test/resources/META-INF/services/io.helidon.inject.spi.InjectionServicesProvider +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (c) 2022 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -io.helidon.inject.api.testsubjects.InjectionServices1Provider -io.helidon.inject.api.testsubjects.InjectionServices2Provider -io.helidon.inject.api.testsubjects.InjectionServices3Provider diff --git a/inject/configdriven/README.md b/inject/configdriven/README.md deleted file mode 100644 index c01957fe14a..00000000000 --- a/inject/configdriven/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Config-driven - -This is a specialization of the [Injection](../)'s that is based upon Helidon's [configuration](../../config) subsystem, and adds support for something called config-driven services using the [@ConfigDriven](./api/src/main/java/io/helidon/inject/configdriven/api/ConfigDriven.java) annotation. When applied to a target service interface it will allow developers to use a higher level aggregation for their application configuration, and then allow the configuration to drive activation of services in the Helidon Injection Framework. The [@ConfigBean](./api/src/main/java/io/helidon/inject/configdriven/api/ConfigBean.java) annotation can be used to customize behavior of a type that acts as a config-bean. - -See the user documentation for more information. - -## Modules -* [api](api) - the config-driven API & SPI. -* [processor](processor) - the annotation processor extensions that should be used when using ConfiguredBy. -* [runtime](runtime) - the runtime support for config-driven services. -* [tests](tests) - tests that can also serve as examples for usage. - -# What is a config-bean? - -Config bean can be any type that -- provides a public static factory method `ConfigBeanType create(io.helidon.common.Config config)` -- is annotated with `@Configured(root = true, prefix = "some.prefix")` - -By referencing it from `@ConfigDriven` annotation, the config-driven annotation processor would take note of the bean, and make sure we can discover it at runtime and create instances from configuration. - -A config-bean can also have `@ConfigBean` annotation to control the way bean instances are created (if we want a default instance, if the bean must have a configured option, and if it repeatable). - -The expectation is that config-beans are created using `helidon-builder-processor`, by annotating a `Blueprint` with `Configured` annotation, and optionally with the `ConfigBean` annotation. - -# What is a config-driven type - -Any service annotated with `@ConfigBean(ConfigBean.class)` is a config-driven service. -Such a service will be added to service registry FOR EACH config bean instance that is discovered from configuration. For repeatable types, each instance has a name obtained from configuration (either the configuration node, or a `name` property), -as a `Named` qualifier. diff --git a/inject/configdriven/api/pom.xml b/inject/configdriven/api/pom.xml deleted file mode 100644 index f9f17077eec..00000000000 --- a/inject/configdriven/api/pom.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject.configdriven - helidon-inject-configdriven-project - 4.2.0-SNAPSHOT - - helidon-inject-configdriven-api - Helidon Injection ConfigDriven ConfiguredBy - - - - io.helidon.inject - helidon-inject-api - - - io.helidon.common - helidon-common-config - - - jakarta.inject - jakarta.inject-api - provided - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - diff --git a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigBean.java b/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigBean.java deleted file mode 100644 index 8ff43eddfa7..00000000000 --- a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigBean.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -/** - * This configured prototype should be acting as a config bean. This means that if appropriate configuration - * exists (must be a root configured type with a defined prefix), an instance will be created from that configuration. - * Additional setup is possible to ensure an instance even if not present in config, and to create default (unnamed) instance. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Documented -@Retention(RetentionPolicy.CLASS) -@Target(java.lang.annotation.ElementType.TYPE) -@Qualifier -public @interface ConfigBean { - /** - * An instance of this bean will be created if there are no instances discovered by the configuration provider(s) post - * startup, and will use all default values annotated using {@code ConfiguredOptions} from the bean interface methods. - *

- * The default value is {@code false}. - * - * @return the default config bean instance using defaults - */ - boolean atLeastOne() default false; - - /** - * Determines whether there can be more than one bean instance of this type. - *

- * If false then only 0..1 behavior will be permissible for active beans in the config registry. If true then {@code > 1} - * instances will be permitted. - *

- * Note: this attribute is dynamic in nature, and therefore cannot be validated at compile time. All violations found to this - * policy will be observed during Services activation. - *

- * The default value is {@code false}. - * - * @return true if repeatable - */ - boolean repeatable() default false; - - /** - * There will always be an instance created with defaults, that will not be named. - *

- * The default value is {@code false}. - * - * @return use the default config instance - */ - boolean wantDefault() default false; -} diff --git a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigBeanFactory.java b/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigBeanFactory.java deleted file mode 100644 index 8b12c9015e5..00000000000 --- a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigBeanFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.api; - -import java.util.List; - -import io.helidon.common.config.Config; - -/** - * Used from generated code. - * Represents the required information to handle config beans, either from {@link ConfigBean} - * annotation, or from other means. - * - * @param type of the config bean - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ConfigBeanFactory { - /** - * Create instances from configuration. - * - * @param config configuration to use (root configuration instance) - * @return list of config bean instances - */ - List> createConfigBeans(Config config); - - /** - * Type of config bean. - * - * @return bean type - */ - Class configBeanType(); - -} diff --git a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigDriven.java b/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigDriven.java deleted file mode 100644 index c984e448a9d..00000000000 --- a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/ConfigDriven.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.api; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -/** - * A config driven service is based on a prototype that is configured from the root of configuration - * (see {@code Configured} in {@code helidon-config-metadata}). - *

- * The annotation is placed on the service implementation (not contract, as we need to understand which type to - * instantiate), and the prototype is expected to be one of the constructor parameters (annotated with {@code @Inject}). - * In case the configured prototype is repeatable, each instance will be named according to the name specified in configuration - * either through {@code name} property, or the config node name. - *

- * Example: - *

- * @ConfigDriven(value = ServerConfig.class, activateByDefault  = true, atLeastOne = true)
- * class ServerImpl {
- *   @Inject
- *   ServerImpl(ServerConfig sc) {
- *   }
- * }
- * 
- * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Documented -@Retention(RetentionPolicy.CLASS) -@Target(java.lang.annotation.ElementType.TYPE) -@Qualifier -public @interface ConfigDriven { - /** - * The prototype class that drives this config driven. - * - * @return the prototype that is configured - */ - Class value(); - - /** - * Determines whether this instance will be activated if created. - * The default value is {@code false}. - * - * @return true if the presence of the config bean has an activation affect - */ - boolean activateByDefault() default false; -} diff --git a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/NamedInstance.java b/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/NamedInstance.java deleted file mode 100644 index 6bcf7376987..00000000000 --- a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/NamedInstance.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.api; - -/** - * Instance, that can be (possibly) named. - * - * @param instance instance of config bean - * @param name the instance may have a name, if this is the default (not named), the name is set to {@value #DEFAULT_NAME} - * @param type of the instance - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public record NamedInstance(T instance, String name) { - /** - * Default name of an instance that is not named for the purpose of injection, for example. - */ - public static final String DEFAULT_NAME = "@default"; -} diff --git a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/package-info.java b/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/package-info.java deleted file mode 100644 index 2384540a110..00000000000 --- a/inject/configdriven/api/src/main/java/io/helidon/inject/configdriven/api/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Config-Driven API. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -package io.helidon.inject.configdriven.api; diff --git a/inject/configdriven/api/src/main/java/module-info.java b/inject/configdriven/api/src/main/java/module-info.java deleted file mode 100644 index 3a84b312e8f..00000000000 --- a/inject/configdriven/api/src/main/java/module-info.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon Injection Config-Driven ConfiguredBy API Module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.configdriven.api { - - requires io.helidon.common.config; - requires io.helidon.inject.api; - - requires static jakarta.inject; - - exports io.helidon.inject.configdriven.api; - -} diff --git a/inject/configdriven/pom.xml b/inject/configdriven/pom.xml deleted file mode 100644 index 09503037c94..00000000000 --- a/inject/configdriven/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - io.helidon.inject.configdriven - helidon-inject-configdriven-project - Helidon Injection ConfigDriven Project - pom - - - api - processor - runtime - - - - - tests - - tests - - - - diff --git a/inject/configdriven/processor/README.md b/inject/configdriven/processor/README.md deleted file mode 100644 index a33fde950c6..00000000000 --- a/inject/configdriven/processor/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# inject-configdriven-processor - -This module should typically should be used at compile-time on the APT classpath. Also note that even though it is called processor it is not technically a processor, but rather a BuilderCreator extension to the base Builder processor. diff --git a/inject/configdriven/processor/pom.xml b/inject/configdriven/processor/pom.xml deleted file mode 100644 index 5e137fc38e1..00000000000 --- a/inject/configdriven/processor/pom.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject.configdriven - helidon-inject-configdriven-project - 4.2.0-SNAPSHOT - - helidon-inject-configdriven-processor - Helidon Injection ConfigDriven Processor - - - - io.helidon.inject - helidon-inject-processor - - - io.helidon.common.processor - helidon-common-processor - - - io.helidon.common - helidon-common-types - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - - diff --git a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBean.java b/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBean.java deleted file mode 100644 index bc70bad7b00..00000000000 --- a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBean.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.processor; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypeValues; - -record ConfigBean(TypeName typeName, - String configPrefix, - ConfigBeanAnnotation annotation) { - private static final TypeName CONFIGURED = TypeName.create("io.helidon.config.metadata.Configured"); - private static final TypeName CONFIGURED_PROTOTYPE = TypeName.create("io.helidon.builder.api.Prototype.Configured"); - private static final TypeName CONFIG = TypeName.create("io.helidon.common.config.Config"); - - public static ConfigBean create(TypeInfo configBeanTypeInfo) { - TypeName typeName; - - // config bean may be the actual prototype, or its blueprint - if (configBeanTypeInfo.hasAnnotation(TypeName.create("io.helidon.builder.api.Prototype.Blueprint"))) { - String className = configBeanTypeInfo.typeName().className(); - if (className.endsWith("Blueprint")) { - className = className.substring(0, className.length() - 9); - typeName = TypeName.builder(configBeanTypeInfo.typeName().genericTypeName()) - .className(className) - .build(); - } else { - throw new IllegalArgumentException("Type annotation with @Prototype.Blueprint does not" - + " end with Blueprint: " + configBeanTypeInfo.typeName()); - } - } else { - typeName = configBeanTypeInfo.typeName(); - - // this type must have a "static Type create(Config config)" - boolean hasConfigFactoryMethod = configBeanTypeInfo.elementInfo() - .stream() - .filter(it -> it.modifiers().contains(TypeValues.MODIFIER_STATIC)) - .filter(it -> it.elementName().equals("create")) - .filter(it -> it.typeName().equals(configBeanTypeInfo.typeName())) - .filter(it -> it.parameterArguments().size() == 1) - .anyMatch(it -> it.parameterArguments().get(0).typeName().equals(CONFIG)); - if (!hasConfigFactoryMethod) { - throw new IllegalArgumentException("ConfigBean type must have a \"static " - + configBeanTypeInfo.typeName().resolvedName() - + " create(io.helidon.common.config.Config config)\" method"); - } - } - - // the type must be annotation with @Configured(root = true, prefix = "something") - boolean isRoot; - String configPrefix; - if (configBeanTypeInfo.hasAnnotation(CONFIGURED)) { - Annotation configured = configBeanTypeInfo.annotation(CONFIGURED); - isRoot = configured.booleanValue("root").orElse(false); - configPrefix = configured.getValue("prefix").orElse(""); - } else if (configBeanTypeInfo.hasAnnotation(CONFIGURED_PROTOTYPE)) { - Annotation configured = configBeanTypeInfo.annotation(CONFIGURED_PROTOTYPE); - isRoot = configured.booleanValue("root").orElse(true); - configPrefix = configured.value().orElse(""); - } else { - throw new IllegalArgumentException("Blueprint must be annotated with @Configured(root = true)" - + " to be eligible to be a ConfigBean: " + configBeanTypeInfo.typeName()); - } - - - - if (!isRoot) { - throw new IllegalArgumentException("Blueprint must be annotated with @Configured(root = true)" - + " to be eligible to be a ConfigBean: " + configBeanTypeInfo.typeName()); - } - - return new ConfigBean(typeName, configPrefix, ConfigBeanAnnotation.create(configBeanTypeInfo)); - } -} diff --git a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBeanAnnotation.java b/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBeanAnnotation.java deleted file mode 100644 index 4c853345d98..00000000000 --- a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBeanAnnotation.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.processor; - -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; - -record ConfigBeanAnnotation(boolean repeatable, - boolean atLeastOne, - boolean wantDefault) { - static final String TYPE_NAME = "io.helidon.inject.configdriven.api.ConfigBean"; - static final TypeName TYPE = TypeName.create(TYPE_NAME); - - static ConfigBeanAnnotation create(TypeInfo typeInfo) { - // this annotation is optional - as long as the type has `Type create(io.helidon.common.Config)` we are fine - return typeInfo.findAnnotation(TYPE) - .map(it -> new ConfigBeanAnnotation(it.getValue("repeatable").map(Boolean::parseBoolean).orElse(false), - it.getValue("atLeastOne").map(Boolean::parseBoolean).orElse(false), - it.getValue("wantDefault").map(Boolean::parseBoolean).orElse(false))) - .orElseGet(() -> new ConfigBeanAnnotation(false, false, false)); - } -} diff --git a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigDrivenAnnotation.java b/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigDrivenAnnotation.java deleted file mode 100644 index 318d5c71724..00000000000 --- a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigDrivenAnnotation.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.processor; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; - -record ConfigDrivenAnnotation(TypeName configBeanType, - boolean activateByDefault) { - static final String TYPE_NAME = "io.helidon.inject.configdriven.api.ConfigDriven"; - static final TypeName TYPE = TypeName.create(TYPE_NAME); - - static ConfigDrivenAnnotation create(TypeInfo typeInfo) { - // this must be available, as it drives our annotation processor - Annotation annotation = typeInfo.findAnnotation(TYPE) - .orElseThrow(); - // value is mandatory on the annotation - return new ConfigDrivenAnnotation(annotation.value().map(TypeName::create).orElseThrow(), - annotation.getValue("activateByDefault") - .map(Boolean::parseBoolean) - .orElse(false)); - } -} diff --git a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigDrivenProcessor.java b/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigDrivenProcessor.java deleted file mode 100644 index 3d006ef1859..00000000000 --- a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigDrivenProcessor.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.processor; - -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import javax.lang.model.element.TypeElement; - -import io.helidon.common.processor.TypeInfoFactory; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.processor.InjectionAnnotationProcessor; -import io.helidon.inject.tools.ServicesToProcess; -import io.helidon.inject.tools.ToolsException; - -/** - * Annotation processor implementation to handle types annotated with {@code ConfigDriven}. - */ -public class ConfigDrivenProcessor extends InjectionAnnotationProcessor { - private static final TypeName CONFIG_DRIVEN_BASE = TypeName.create( - "io.helidon.inject.configdriven.runtime.ConfigDrivenServiceProviderBase"); - private static final TypeName NAMED_INSTANCE = TypeName.create("io.helidon.inject.configdriven.api.NamedInstance"); - - /** - * Required constructor for a service loaded via {@link java.util.ServiceLoader}. - */ - public ConfigDrivenProcessor() { - super(true); - } - - @Override - protected Set supportedServiceClassTargetAnnotations() { - Set supported = new HashSet<>(super.supportedServiceClassTargetAnnotations()); - supported.add(ConfigDrivenAnnotation.TYPE_NAME); - return supported; - } - - @Override - protected void processExtensions(ServicesToProcess services, - TypeInfo service, - Set serviceTypeNamesToCodeGenerate, - Collection allElementsOfInterest) { - - if (!service.hasAnnotation(ConfigDrivenAnnotation.TYPE)) { - return; - } - - ConfigDrivenAnnotation configDriven = ConfigDrivenAnnotation.create(service); - // the type must be either a valid prototype, or a prototype blueprint (in case this is the same module) - if ("".equals(configDriven.configBeanType().className())) { - throw new ToolsException("The config bean type must be set to the Blueprint type if they are within the same " - + "module! Failed on: " + service.typeName().resolvedName()); - } - TypeInfo configBeanTypeInfo = TypeInfoFactory.create(processingEnv, asElement(configDriven.configBeanType())) - .orElseThrow(); - - ConfigBean configBean = ConfigBean.create(configBeanTypeInfo); - /* - Now we have all the information we need - - type that is annotated as @ConfigDriven - - which type drives it - - config prefix for the type driving it - - if repeatable etc. - */ - - // we do not support inheritance of config driven (for now) - // now stuff needed for activator generation - TypeName serviceType = service.typeName(); - TypeName activatorImplType = activatorCreator().toActivatorImplTypeName(serviceType); - TypeName superType = TypeName.builder(CONFIG_DRIVEN_BASE) - .addTypeArgument(serviceType) - .addTypeArgument(configBean.typeName()) - .build(); - boolean accepted = services.addParentServiceType(serviceType, superType, Optional.of(true)); - assert (accepted); - - services.defaultConstructor(serviceType, generateConstructor()); - generateCode(activatorImplType, - serviceType, - configBean, - superType, - configDriven.activateByDefault()) - .forEach(fn -> services.addExtraCodeGen(serviceType, fn)); - } - - private String generateConstructor() { - return "super(\"root\");\n" - + "\n" - + "\t\tthis.configBean = null;\n" - + "\t\tserviceInfo(serviceInfo);"; - } - - private List generateCode(TypeName activatorImplType, - TypeName serviceType, - ConfigBean configBean, - TypeName superType, - boolean activateByDefault) { - TypeName namedInstanceWithGeneric = TypeName.builder(NAMED_INSTANCE) - .addTypeArgument(configBean.typeName()) - .build(); - String configBeanName = configBean.typeName().resolvedName(); - - return List.of( - // config bean field - "\n\tprivate final " + configBeanName + " configBean;\n", - // constructor with NamedInstance - "\n\tprivate " + activatorImplType.className() + "(" + namedInstanceWithGeneric.resolvedName() - + " configBean) {\n" - + "\t\tsuper(configBean.name());\n" - + "\t\tassertIsRootProvider(false, true);\n" - + "\t\tserviceInfo(serviceInfo);\n" - + "\t\tthis.configBean = configBean.instance();\n" - + "\t}\n", - // create config beans from config - generateCreateConfigBeans(configBean, namedInstanceWithGeneric), - // configBeanType() - "\n\t@Override\n" - + "\tpublic Class<" + configBeanName + "> configBeanType() {\n" - + "\t\treturn " + configBeanName + ".class;\n" - + "\t}\n", - // createInstance(NamedInstance) - "\n\t@Override\n" - + "\tprotected " + superType.resolvedName() + " createInstance(" - + namedInstanceWithGeneric.resolvedName() + " " - + "configBean) {\n" - + "\t\treturn new " + activatorImplType.className() + "(configBean);\n" - + "\t}\n", - // drivesActivation() - "\n\t@Override\n" - + "\tprotected boolean drivesActivation() {\n" - + "\t\treturn " + activateByDefault + ";\n" - + "\t}\n", - // configBean() - "\n\t@Override\n" - + "\tpublic " + configBeanName + " configBean() {\n" - + "\t\tif (isRootProvider()) {\n" - + "\t\t\tthrow new NullPointerException(\"Config bean is not available on root config driven" - + " instance\");\n" - + "\t\t}\n" - + "\t\treturn configBean;\n" - + "\t}\n" - ); - } - - private String generateCreateConfigBeans(ConfigBean configBean, TypeName namedInstanceWithGeneric) { - String prefix = configBean.configPrefix(); - boolean atLeastOne = configBean.annotation().atLeastOne(); - boolean repeatable = configBean.annotation().repeatable(); - boolean wantDefault = configBean.annotation().wantDefault(); - - StringBuilder method = new StringBuilder(); - method.append("\n\t@Override\n") - .append("\tpublic List<") - .append(namedInstanceWithGeneric.resolvedName()) - .append("> createConfigBeans(io.helidon.common.config.Config config){\n") - .append("\t\tvar beanConfig = config.get(\"") - .append(prefix) - .append("\");\n") - .append("\t\tif (!beanConfig.exists()) {\n"); - - // the config does not exist - if (atLeastOne) { - // throw an exception, we need at least one instance - method.append("\t\t\tthrow new io.helidon.common.config.ConfigException(\""); - if (repeatable) { - method.append("Expecting list of configurations"); - } else { - method.append("Expecting configuration"); - } - method.append(" at \\\"") - .append(configBean.configPrefix()) - .append("\\\"\");"); - } else if (wantDefault) { - method.append("\t\t\treturn List.of(new io.helidon.inject.configdriven.api.NamedInstance<>(") - .append(configBean.typeName().resolvedName()) - .append(".create(io.helidon.common.config.Config.empty()), io.helidon.inject.configdriven.api.NamedInstance" - + ".DEFAULT_NAME));\n"); - } else { - method.append("\t\t\treturn List.of();\n"); - } - method.append("\t\t}\n"); - - // the bean config does exist - if (repeatable) { - method.append("\t\treturn createRepeatableBeans(beanConfig, ") - .append(wantDefault) - .append(", ") - .append(configBean.typeName().resolvedName()) - .append("::create);\n"); - } else { - method.append("\t\tif (beanConfig.isList()) {\n") - .append("\t\t\tthrow new io.helidon.common.config.ConfigException(\"Expecting a single node at \\\"") - .append(configBean.configPrefix()) - .append("\\\", but got a list\");\n") - .append("\t\t}\n"); - method.append("\t\treturn java.util.List.of(new ") - .append(NAMED_INSTANCE.resolvedName()) - .append("<>(") - .append(configBean.typeName().resolvedName()) - .append(".create(beanConfig), ") - .append(NAMED_INSTANCE.resolvedName()) - .append(".DEFAULT_NAME));\n"); - } - method.append("\t}\n"); - - return method.toString(); - } - - private TypeElement asElement(TypeName typeName) { - return processingEnv.getElementUtils().getTypeElement(typeName.resolvedName()); - } -} diff --git a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/package-info.java b/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/package-info.java deleted file mode 100644 index 7c3b5577155..00000000000 --- a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Config-Driven processor. - */ -package io.helidon.inject.configdriven.processor; diff --git a/inject/configdriven/processor/src/main/java/module-info.java b/inject/configdriven/processor/src/main/java/module-info.java deleted file mode 100644 index 0257fc29e2c..00000000000 --- a/inject/configdriven/processor/src/main/java/module-info.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon Inject ConfiguredBy Processor module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.configdriven.processor { - - requires io.helidon.common.processor; - requires io.helidon.common.types; - requires io.helidon.common; - requires io.helidon.inject.processor; - requires java.compiler; - - exports io.helidon.inject.configdriven.processor; - - provides javax.annotation.processing.Processor with - io.helidon.inject.configdriven.processor.ConfigDrivenProcessor; - -} diff --git a/inject/configdriven/runtime/README.md b/inject/configdriven/runtime/README.md deleted file mode 100644 index 689908043b9..00000000000 --- a/inject/configdriven/runtime/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# inject-configdriven-runtime - -This module should typically be used by anyone needing Helidon Injection's Config-Driven Services at runtime. diff --git a/inject/configdriven/runtime/pom.xml b/inject/configdriven/runtime/pom.xml deleted file mode 100644 index 2b8ce719bbf..00000000000 --- a/inject/configdriven/runtime/pom.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject.configdriven - helidon-inject-configdriven-project - 4.2.0-SNAPSHOT - - helidon-inject-configdriven-runtime - Helidon Injection ConfigDriven Runtime Services - - - - io.helidon.inject.configdriven - helidon-inject-configdriven-api - - - io.helidon.config - helidon-config - - - io.helidon.inject - helidon-inject-runtime - - - jakarta.inject - jakarta.inject-api - - - io.helidon.config - helidon-config-metadata - true - - - io.helidon.common.features - helidon-common-features-api - true - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.inject - helidon-inject-testing - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - org.mockito - mockito-core - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - io.helidon.common.features - helidon-common-features-processor - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - io.helidon.common.features - helidon-common-features-processor - ${helidon.version} - - - - - - - diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigBeanRegistry.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigBeanRegistry.java deleted file mode 100644 index 658ce071d30..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigBeanRegistry.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.runtime; - -import java.util.List; -import java.util.Map; - -import io.helidon.inject.configdriven.api.ConfigBean; -import io.helidon.inject.configdriven.api.NamedInstance; - -/** - * Manages the set of active {@link ConfigBean}'s, along with whether the application is - * configured to support dynamic aspects (i.e., dynamic in content, dynamic in lifecycle, etc.). - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ConfigBeanRegistry { - /** - * Config bean registry instance for the current VM. - * - * @return config bean registry - */ - static ConfigBeanRegistry instance() { - return ConfigBeanRegistryImpl.CONFIG_BEAN_REGISTRY.get(); - } - - /** - * The config bean registry is initialized as part of Helidon Injection's initialization, which happens when the service - * registry is initialized and bound. - * - * @return true if the config bean registry has been initialized - */ - boolean ready(); - - /** - * All active configuration beans (including default instances). - * - * @return map of all configuration beans, key is the config bean class, values are named instances - */ - Map, List>> allConfigBeans(); -} diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigBeanRegistryImpl.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigBeanRegistryImpl.java deleted file mode 100644 index 73260f74457..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigBeanRegistryImpl.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.runtime; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; - -import io.helidon.common.LazyValue; -import io.helidon.common.config.Config; -import io.helidon.common.config.ConfigException; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionException; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesHolder; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.configdriven.api.ConfigBean; -import io.helidon.inject.configdriven.api.ConfigBeanFactory; -import io.helidon.inject.configdriven.api.NamedInstance; - -/** - * The default implementation for {@link ConfigBeanRegistry}. - */ -@SuppressWarnings("unchecked") -class ConfigBeanRegistryImpl implements ConfigBeanRegistry, Resettable { - static final LazyValue CONFIG_BEAN_REGISTRY = LazyValue.create(ConfigBeanRegistryImpl::new); - - private static final System.Logger LOGGER = System.getLogger(ConfigBeanRegistryImpl.class.getName()); - - private final AtomicBoolean registeredForReset = new AtomicBoolean(); - private final AtomicBoolean initializing = new AtomicBoolean(); - - // map of config bean types to their factories (only for used config beans, that have a config driven service associated) - private final Map, ConfigBeanFactory> configBeanFactories = new ConcurrentHashMap<>(); - // map of config bean types to the config driven types - private final Map, Set>> configDrivenByConfigBean = new ConcurrentHashMap<>(); - private final Map, ConfiguredServiceProvider> configDrivenFactories = new ConcurrentHashMap<>(); - // map of config bean types to instances (list may be empty if no instance exists) - private final Map, List>> configBeanInstances = new ConcurrentHashMap<>(); - - private CountDownLatch initialized = new CountDownLatch(1); - - ConfigBeanRegistryImpl() { - } - - @Override - public Map, List>> allConfigBeans() { - return Map.copyOf(configBeanInstances); - } - - @Override - public boolean reset(boolean deep) { - System.Logger.Level level = (isInitialized() && InjectionServices.isDebugEnabled()) - ? System.Logger.Level.INFO : System.Logger.Level.DEBUG; - LOGGER.log(level, "Resetting"); - configBeanFactories.clear(); - configDrivenByConfigBean.clear(); - configDrivenFactories.clear(); - configBeanInstances.clear(); - initializing.set(false); - initialized = new CountDownLatch(1); - registeredForReset.set(false); - - return true; - } - - @Override - public boolean ready() { - return isInitialized(); - } - - /** - * Binds a {@link ConfiguredServiceProvider} to the - * {@link ConfigBean} annotation it is configured by. - * - * @param configuredServiceProvider the configured service provider - * @param configuredByQualifier the qualifier associated with the {@link ConfigBean} - * @throws io.helidon.config.ConfigException if the bind operation encountered an error - */ - void bind(ConfiguredServiceProvider configuredServiceProvider, - Qualifier configuredByQualifier) { - Objects.requireNonNull(configuredServiceProvider); - Objects.requireNonNull(configuredByQualifier); - - if (initializing.get()) { - throw new ConfigException("Unable to bind config post initialization: " - + configuredServiceProvider.description()); - } - - Class configBeanType = configuredServiceProvider.configBeanType(); - Class configDrivenType = configuredServiceProvider.serviceType(); - - if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) { - LOGGER.log(System.Logger.Level.DEBUG, "Binding " + configDrivenType - + " with " + configuredByQualifier.value()); - } - - if (!configDrivenByConfigBean.computeIfAbsent(configBeanType, it -> new LinkedHashSet<>()) - .add(configDrivenType)) { - assert (true) : "duplicate service provider initialization occurred: " + configBeanType + ", " + configDrivenType; - } - configDrivenFactories.put(configDrivenType, configuredServiceProvider); - configBeanFactories.put(configBeanType, configuredServiceProvider); - } - - /** - * The first call to this initialize the bean registry, by loading all the backing configuration from the config - * subsystem. - */ - void initialize() { - if (registeredForReset.compareAndSet(false, true)) { - ResettableHandler.addRegistry(this); - } - try { - if (initializing.getAndSet(true)) { - // all threads should wait for the leader (and the config bean registry) to have been fully initialized - initialized.await(); - return; - } - - Config config = InjectionServices.realizedGlobalBootStrap().config().orElse(null); - if (config == null) { - LOGGER.log(System.Logger.Level.WARNING, - "Unable to initialize - there is no config to read - be sure to initialize " - + Bootstrap.class.getName() + " config prior to service activation."); - reset(true); - return; - } - - LOGGER.log(System.Logger.Level.DEBUG, "Initializing"); - initialize(config); - // we are now ready and initialized - initialized.countDown(); - } catch (Throwable t) { - InjectionException e = new InjectionServiceProviderException("Error while initializing config bean registry", t); - LOGGER.log(System.Logger.Level.ERROR, e.getMessage(), e); - reset(true); - throw e; - } - } - - protected boolean isInitialized() { - return (0 == initialized.getCount()); - } - - @SuppressWarnings("rawtypes") - private void initialize(Config rootConfiguration) { - if (configBeanFactories.isEmpty()) { - LOGGER.log(System.Logger.Level.DEBUG, "No config driven services found"); - return; - } - - for (ConfigBeanFactory beanFactory : configBeanFactories.values()) { - Class configBeanType = beanFactory.configBeanType(); - List> configBeans = beanFactory.createConfigBeans(rootConfiguration); - for (NamedInstance configBean : configBeans) { - configBeanInstances.computeIfAbsent(configBeanType, type -> new ArrayList<>()) - .add(configBean); - } - - Set> configDrivenTypes = configDrivenByConfigBean.get(configBeanType); - if (configDrivenTypes == null) { - LOGGER.log(System.Logger.Level.WARNING, "Unexpected state of config bean registry, " - + "config bean does not have any config driven types. Config bean type: " + configBeanType); - continue; - } - - // for each config driven type, create new instances for each discovered config bean - for (Class configDrivenType : configDrivenTypes) { - ConfiguredServiceProvider configuredServiceProvider = configDrivenFactories.get(configDrivenType); - if (configuredServiceProvider == null) { - LOGGER.log(System.Logger.Level.WARNING, "Unexpected state of config bean registry, " - + "config driven does not have associated service provider. Config bean type: " - + configBeanType); - continue; - } - for (NamedInstance configBean : configBeans) { - // now we have a tuple of a config bean instance and a config driven service provider - configuredServiceProvider.registerConfigBean(configBean); - } - } - } - } - - private static final class ResettableHandler extends InjectionServicesHolder { - @Deprecated - private ResettableHandler() { - } - - private static void addRegistry(Resettable resettable) { - InjectionServicesHolder.addResettable(resettable); - } - } -} diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigDrivenServiceProviderBase.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigDrivenServiceProviderBase.java deleted file mode 100644 index bc52c98d666..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigDrivenServiceProviderBase.java +++ /dev/null @@ -1,667 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.runtime; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.stream.Collectors; - -import io.helidon.common.config.Config; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.Annotations; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.CallingContext; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.Event; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; -import io.helidon.inject.api.ServiceProviderInjectionException; -import io.helidon.inject.api.ServiceProviderProvider; -import io.helidon.inject.configdriven.api.ConfigDriven; -import io.helidon.inject.configdriven.api.NamedInstance; -import io.helidon.inject.runtime.AbstractServiceProvider; -import io.helidon.inject.spi.InjectionResolver; - -import static io.helidon.inject.api.CommonQualifiers.WILDCARD_NAMED; -import static io.helidon.inject.configdriven.runtime.ConfigDrivenUtils.hasValue; -import static io.helidon.inject.configdriven.runtime.ConfigDrivenUtils.isBlank; -import static io.helidon.inject.runtime.InjectionExceptions.toErrorMessage; - -/** - * Abstract base for any config-driven-service. - * - * @param the type of the service this provider manages - * @param the type of config beans that this service is configured by - */ -// special note: many of these methods are referenced in code generated code! -public abstract class ConfigDrivenServiceProviderBase extends AbstractServiceProvider - implements ConfiguredServiceProvider, - ServiceProviderProvider, - InjectionPointProvider, - InjectionResolver { - private static final System.Logger LOGGER = System.getLogger(ConfigDrivenServiceProviderBase.class.getName()); - private static final Qualifier EMPTY_CONFIGURED_BY = Qualifier.create(ConfigDriven.class); - - private final AtomicReference isRootProvider = new AtomicReference<>(); - private final AtomicReference> rootProvider = new AtomicReference<>(); - private final AtomicBoolean initialized = new AtomicBoolean(); - private final AtomicReference initializationCallingContext - = new AtomicReference<>(); // used only when we are in inject.debug mode - // map of name to config driven service provider (non-root) - private final Map> managedConfiguredServicesMap - = new ConcurrentHashMap<>(); - private final String instanceId; - - /** - * The default constructor. - * - * @param instanceId of this provider, root provider is hardcoded to {@code root}, managed instances are named based on - * the config bean name - */ - protected ConfigDrivenServiceProviderBase(String instanceId) { - this.instanceId = instanceId; - } - - /** - * Called during initialization to register a loaded config bean. - * - * @param configBean the config bean - */ - @Override - public final void registerConfigBean(NamedInstance configBean) { - Objects.requireNonNull(configBean); - assertIsInitializing(); - - Object prev = managedConfiguredServicesMap.put(configBean.name(), createInstance(configBean)); - assert (prev == null); - } - - @Override - public boolean reset(boolean deep) { - super.reset(deep); - managedConfiguredServicesMap.clear(); - isRootProvider.set(null); - rootProvider.set(null); - initialized.set(false); - initializationCallingContext.set(null); - return true; - } - - @Override - public boolean isRootProvider() { - Boolean root = isRootProvider.get(); - return (root != null && root && rootProvider.get() == null); - } - - @Override - public Optional> rootProvider() { - return Optional.ofNullable(rootProvider.get()); - } - - @Override - public void rootProvider(ServiceProvider root) { - assertIsRootProvider(false, false); - assert (!isRootProvider() && rootProvider.get() == null && this != root); - boolean set = rootProvider.compareAndSet(null, - (ConfigDrivenServiceProviderBase) Objects.requireNonNull(root)); - assert (set); - } - - @Override - public void injectionServices(Optional injectionServices) { - assertIsInitializing(); - assertIsRootProvider(true, false); - - if (isRootProvider()) { - // override out service info to account for any named lookup - ServiceInfo serviceInfo = Objects.requireNonNull(serviceInfo()); - if (!serviceInfo.qualifiers().contains(WILDCARD_NAMED)) { - serviceInfo = ServiceInfo.builder(serviceInfo) - .addQualifier(WILDCARD_NAMED) - .build(); - serviceInfo(serviceInfo); - } - - // bind to the config bean registry ... but, don't yet resolve! - ConfigBeanRegistryImpl cbr = ConfigBeanRegistryImpl.CONFIG_BEAN_REGISTRY.get(); - if (cbr != null) { - Optional configuredByQualifier = serviceInfo.qualifiers().stream() - .filter(q -> q.typeName().name().equals(ConfigDriven.class.getName())) - .findFirst(); - assert (configuredByQualifier.isPresent()); - cbr.bind(this, configuredByQualifier.get()); - } - } - // do this as the last thing, so our ancestor does not think we are already initialized when overwriting service info - super.injectionServices(injectionServices); - } - - @Override - public void onPhaseEvent(Event event, - Phase phase) { - if (phase == Phase.POST_BIND_ALL_MODULES) { - assertIsInitializing(); - - if (Phase.INIT == currentActivationPhase()) { - LogEntryAndResult logEntryAndResult = createLogEntryAndResult(Phase.PENDING); - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.PENDING); - } - - // one of the configured services need to "tickle" the bean registry to initialize - ConfigBeanRegistryImpl cbr = ConfigBeanRegistryImpl.CONFIG_BEAN_REGISTRY.get(); - if (cbr != null) { - cbr.initialize(); - - // pre-initialize ourselves - if (isRootProvider()) { - // pre-activate our managed services - managedConfiguredServicesMap.values() - .forEach(this::innerPreActivateManagedService); - } - } - } else if (phase == Phase.FINAL_RESOLVE) { - // post-initialize ourselves - if (isRootProvider() - && drivesActivation()) { - ContextualServiceQuery query = ContextualServiceQuery - .builder().serviceInfoCriteria(InjectionServices.EMPTY_CRITERIA) - .build(); - maybeActivate(query); - } - - assertInitialized(); - resolveConfigDrivenServices(); - } else if (phase == Phase.SERVICES_READY) { - assertIsInitialized(); - activateConfigDrivenServices(); - } - } - - // note that all responsibilities to resolve is delegated to the root provider - @Override - public Optional resolve(InjectionPointInfo ipInfo, - InjectionServices injectionServices, - ServiceProvider serviceProvider, - boolean resolveIps) { - if (resolveIps) { - assert (isRootProvider()); - // too early to resolve... - return Optional.empty(); - } - - ServiceInfoCriteria dep = ipInfo.dependencyToServiceInfo(); - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addContractImplemented(configBeanType()) - .build(); - if (!dep.matchesContracts(criteria)) { - return Optional.empty(); // we are being injected with neither a config bean nor a service that matches ourselves - } - - // if we are here then we are asking for a config bean for ourselves, or a slave/managed instance - if (!dep.qualifiers().isEmpty()) { - throw new ServiceProviderInjectionException("cannot use qualifiers while injecting config beans for self", this); - } - - if (isRootProvider()) { - return Optional.of(configBeanType()); - } - - return Optional.of(configBean()); - } - - /** - * Here we are only looking for service providers, not service instances. What we need to do here is to determine - * whether to (a) include root providers, (b) include slave providers, or (c) include both. - *

- * The result depends on the type of this provider instance. - * Here is the heuristic: - *

    - *
  • if this is a slave then simply use the standard matching behavior. - *

    - * If, however, we are the root provider then the additional heuristic is applied: - *

  • if the request mentions the {@link ConfigDriven} qualifier w/ no value specified - * then the caller is only interested in the root provider. - *
  • if the request mentions the {@link ConfigDriven} qualifier w/ a value specified - * then the caller is only interested in the slave providers. - *
  • if the request is completely empty then they are interested in everything - the root - * provider as well as the slave providers. - *
  • if there is no slaves under management then they must be interested in the root provider. - *
  • the fallback is to use standard matching using the criteria provided and only include the slaves. - *
- * - * @param criteria the injection point criteria that must match - * @param wantThis if this instance matches criteria, do we want to return this instance as part of the result - * @param thisAlreadyMatches an optimization that signals to the implementation that this instance has already - * matched using the standard service info matching checks - * @return the list of matching service providers based upon the context and criteria provided - */ - @Override - public List> serviceProviders(ServiceInfoCriteria criteria, - boolean wantThis, - boolean thisAlreadyMatches) { - if (isRootProvider()) { - Set qualifiers = criteria.qualifiers(); - Optional configuredByQualifier = Annotations - .findFirst(EMPTY_CONFIGURED_BY.typeName(), qualifiers); - boolean hasValue = configuredByQualifier.isPresent() - && hasValue(configuredByQualifier.get().value().orElse(null)); - boolean blankCriteria = qualifiers.isEmpty() && isBlank(criteria); - boolean slavesQualify = !managedConfiguredServicesMap.isEmpty() - && (blankCriteria || hasValue || configuredByQualifier.isEmpty()); - boolean rootQualifies = wantThis - && ( - blankCriteria - || ( - managedConfiguredServicesMap.isEmpty() - && ( - qualifiers.isEmpty() - || qualifiers.contains(WILDCARD_NAMED)) - || (!hasValue && configuredByQualifier.isPresent()))); - - if (slavesQualify) { - List> slaves = new ArrayList<>(managedServiceProviders(criteria) - .values()); - - if (rootQualifies) { - List> result = new ArrayList<>(); - if (thisAlreadyMatches || serviceInfo().matches(criteria)) { - result.add(this); - } - result.addAll(slaves); - // no need to sort using the comparator here since we should already be in the proper order... - return result; - } else { - return slaves; - } - } else if (rootQualifies - && (thisAlreadyMatches || serviceInfo().matches(criteria))) { - if (!hasValue && managedConfiguredServicesMap.isEmpty()) { - return List.of(new UnconfiguredServiceProvider<>(this)); - } - return List.of(this); - } - } else { // this is a slave instance ... - if (thisAlreadyMatches || serviceInfo().matches(criteria)) { - return List.of(this); - } - } - - return List.of(); - } - - @Override - public Map> managedServiceProviders(ServiceInfoCriteria criteria) { - if (!isRootProvider()) { - assert (managedConfiguredServicesMap.isEmpty()); - return Map.of(); - } - - Map> map = managedConfiguredServicesMap.entrySet() - .stream() - .filter(e -> e.getValue().serviceInfo().matches(criteria)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - if (map.size() <= 1) { - return map; - } - - Map> result = new TreeMap<>(NameComparator.instance()); - result.putAll(map); - return result; - } - - @Override - @SuppressWarnings("unchecked") - public Optional first(ContextualServiceQuery query) { - if (!isRootProvider()) { - return maybeActivate(query); - } - - // we are root provider - if (Phase.ACTIVE != currentActivationPhase()) { - LogEntryAndResult logEntryAndResult = createLogEntryAndResult(Phase.ACTIVE); - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVE); - } - - ServiceInfoCriteria criteria = query.serviceInfoCriteria(); - List> qualifiedProviders = serviceProviders(criteria, false, true); - for (ServiceProvider qualifiedProvider : qualifiedProviders) { - assert (this != qualifiedProvider); - Optional serviceOrProvider = qualifiedProvider.first(query); - if (serviceOrProvider.isPresent()) { - return (Optional) serviceOrProvider; - } - } - - if (query.expected()) { - throw expectedQualifiedServiceError(query); - } - - return Optional.empty(); - } - - @Override - @SuppressWarnings("unchecked") - public List list(ContextualServiceQuery query) { - if (!isRootProvider()) { - Optional serviceOrProvider = maybeActivate(query); - if (query.expected() && serviceOrProvider.isEmpty()) { - throw expectedQualifiedServiceError(query); - } - return serviceOrProvider.map(List::of).orElseGet(List::of); - } - - // we are root - Map> matching = managedServiceProviders(query.serviceInfoCriteria()); - if (!matching.isEmpty()) { - List result = matching.values().stream() - .map(it -> it.first(query)) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - if (!result.isEmpty()) { - return (List) result; - } - } - - if (!query.expected()) { - return List.of(); - } - - throw expectedQualifiedServiceError(query); - } - - /** - * Configurable services by their very nature are not compile-time bindable during application creation. - * - * @return empty, signaling that we are not bindable - */ - @Override - public Optional> serviceProviderBindable() { - return Optional.empty(); - } - - /** - * Creates a new instance of this type of configured service provider, along with the configuration bean - * associated with the service. - * - * @param configBean the config bean - * @return the created instance injected with the provided config bean - */ - protected abstract ConfigDrivenServiceProviderBase createInstance(NamedInstance configBean); - - /** - * After the gathering dependency phase, we will short circuit directly to the finish line. - */ - @Override - protected void doConstructing(LogEntryAndResult logEntryAndResult) { - if (isRootProvider()) { - boolean shouldBeActive = (drivesActivation() && !managedConfiguredServicesMap.isEmpty()); - Phase setPhase = (shouldBeActive) ? Phase.ACTIVE : Phase.PENDING; - startTransitionCurrentActivationPhase(logEntryAndResult, setPhase); - onFinished(logEntryAndResult); - return; - } - - super.doConstructing(logEntryAndResult); - } - - @Override - protected String identitySuffix() { - return "{" + instanceId + "}"; - } - - /** - * Instance id associated with this instance. - * - * @return instance id - */ - protected String instanceId() { - return instanceId; - } - - @Override - protected void serviceInfo(ServiceInfo serviceInfo) { - // this might appear strange, but since activators can inherit from one another this is in place to trigger - // only when the most derived activator ctor is setting its serviceInfo. - boolean isThisOurServiceInfo = TypeName.create(serviceType()).equals(serviceInfo.serviceTypeName()); - if (isThisOurServiceInfo) { - assertIsInitializing(); - assertIsRootProvider(true, false); - - // override our service info to account for any named lookup - if (isRootProvider() && !serviceInfo.qualifiers().contains(WILDCARD_NAMED)) { - serviceInfo = ServiceInfo.builder(serviceInfo) - .addQualifier(WILDCARD_NAMED) - .build(); - } - } - - super.serviceInfo(serviceInfo); - } - - @Override - protected System.Logger logger() { - return LOGGER; - } - - @Override - protected void doPreDestroying(LogEntryAndResult logEntryAndResult) { - if (isRootProvider()) { - managedConfiguredServicesMap.values() - .forEach(csp -> { - LogEntryAndResult cspLogEntryAndResult = csp.createLogEntryAndResult(Phase.DESTROYED); - csp.doPreDestroying(cspLogEntryAndResult); - }); - } - super.doPreDestroying(logEntryAndResult); - } - - @Override - protected void doDestroying(LogEntryAndResult logEntryAndResult) { - super.doDestroying(logEntryAndResult); - } - - @Override - protected void onFinalShutdown() { - if (isRootProvider()) { - managedConfiguredServicesMap.values() - .stream() - .filter(csp -> csp.currentActivationPhase().eligibleForDeactivation()) - .forEach(ConfigDrivenServiceProviderBase::onFinalShutdown); - } - - this.initialized.set(false); - this.managedConfiguredServicesMap.clear(); - - super.onFinalShutdown(); - } - - /** - * Maybe transition into being a root provider if we are the first to claim it. Otherwise, we are a slave being managed. - * - * @param isRootProvider true if an asserting is being made to claim root or claim managed slave - * @param expectSet true if this is a strong assertion, and if not claimed an exception will be thrown - */ - // special note: this is referred to in code generated code! - protected void assertIsRootProvider(boolean isRootProvider, - boolean expectSet) { - boolean set = this.isRootProvider.compareAndSet(null, isRootProvider); - if (!set && expectSet) { - throw new InjectionServiceProviderException(description() + " was already initialized", null, this); - } - assert (!isRootProvider || rootProvider.get() == null); - } - - /** - * Return true if this service is driven to activation during startup (and provided it has some config). - * See {@link ConfigDriven#activateByDefault()}. - * - * @return true if this service is driven to activation during startup - */ - protected abstract boolean drivesActivation(); - - /** - * Transition into an initialized state. - */ - void assertInitialized() { - assertIsInitializing(); - assert ( - !drivesActivation() - || isAlreadyAtTargetPhase(InjectionServices.terminalActivationPhase()) - || managedConfiguredServicesMap.isEmpty()); - this.initialized.set(true); - } - - void assertIsInitializing() { - if (initialized.get()) { - CallingContext callingContext = initializationCallingContext.get(); - String desc = description() + " was previously initialized"; - String msg = (callingContext == null) ? toErrorMessage(desc) : toErrorMessage(callingContext, desc); - throw new InjectionServiceProviderException(msg, this); - } - } - - void assertIsInitialized() { - if (!initialized.get()) { - throw new InjectionServiceProviderException(description() + " was expected to be initialized", this); - } - } - - void resolveConfigDrivenServices() { - assertIsInitialized(); - assert (isRootProvider()); - - if (managedConfiguredServicesMap.isEmpty()) { - if (logger().isLoggable(System.Logger.Level.DEBUG)) { - logger().log(System.Logger.Level.DEBUG, "no configured services for: " + description()); - } - return; - } - - // accept and resolve config - managedConfiguredServicesMap.values().forEach(csp -> { - if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) { - LOGGER.log(System.Logger.Level.DEBUG, "Resolving config for " + csp); - } - - LogEntryAndResult logEntryAndResult = createLogEntryAndResult(Phase.PENDING); - try { - csp.startTransitionCurrentActivationPhase(logEntryAndResult, Phase.PENDING); - } catch (Throwable t) { - csp.onFailedFinish(logEntryAndResult, t, true); - } - }); - } - - protected final List> createRepeatableBeans(Config config, - boolean wantDefault, - Function factory) { - Map> instances = new TreeMap<>(NameComparator.instance()); - - List childNodes = config.asNodeList().orElseGet(List::of); - boolean isList = config.isList(); - - for (Config childNode : childNodes) { - String name = childNode.name(); // by default use the current node name - for lists, this would be the index - name = isList ? childNode.get("name").asString().orElse(name) : name; // use "name" node if list and present - instances.put(name, new NamedInstance<>(factory.apply(childNode), name)); - } - - if (wantDefault && !instances.containsKey(NamedInstance.DEFAULT_NAME)) { - instances.put(NamedInstance.DEFAULT_NAME, - new NamedInstance<>(factory.apply(Config.empty()), NamedInstance.DEFAULT_NAME)); - } - - return List.copyOf(instances.values()); - } - - private void activateConfigDrivenServices() { - assertIsInitialized(); - assert (isRootProvider()); - - if (managedConfiguredServicesMap.isEmpty()) { - return; - } - - if (!drivesActivation()) { - if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) { - LOGGER.log(System.Logger.Level.DEBUG, "drivesActivation disabled for: " + description()); - } - return; - } - - managedConfiguredServicesMap.values().forEach(ConfigDrivenServiceProviderBase::activateManagedService); - } - - private void innerActivate() { - // this may go into a wait state if other threads are trying to also initialize at the same time - expected behavior - ContextualServiceQuery query = ContextualServiceQuery - .builder().serviceInfoCriteria(InjectionServices.EMPTY_CRITERIA) - .build(); - Optional service = maybeActivate(query); // triggers the post-construct - if (service.isPresent() && LOGGER.isLoggable(System.Logger.Level.DEBUG)) { - LOGGER.log(System.Logger.Level.DEBUG, "finished activating: " + service); - } - } - - private void activateManagedService() { - if (Phase.ACTIVE != currentActivationPhase()) { - innerActivate(); - } - } - - private void innerPreActivateManagedService(ConfigDrivenServiceProviderBase instance) { - if (LOGGER.isLoggable(System.Logger.Level.DEBUG)) { - LOGGER.log(System.Logger.Level.DEBUG, "creating: " + serviceType() - + " with config instance id: " + instance.instanceId()); - } - - // cannot pre-activate root itself, and this method is ONLY called on root provider - assert (instance != this); - - ServiceInfo newServiceInfo = ServiceInfo.builder(instance.serviceInfo()) - .addQualifier(Qualifier.createNamed(instance.instanceId())) - .build(); - - // override our service info - instance.serviceInfo(newServiceInfo); - instance.injectionServices(injectionServices()); - instance.rootProvider(this); - - if (logger().isLoggable(System.Logger.Level.DEBUG)) { - logger().log(System.Logger.Level.DEBUG, "config instance successfully initialized: " - + id() + ":" + newServiceInfo.qualifiers()); - } - } - -} diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigDrivenUtils.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigDrivenUtils.java deleted file mode 100644 index 130ffd85129..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfigDrivenUtils.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.runtime; - -import io.helidon.inject.api.ServiceInfoCriteria; - -final class ConfigDrivenUtils { - - private ConfigDrivenUtils() { - } - - static boolean isBlank(ServiceInfoCriteria criteria) { - assert (criteria.externalContractsImplemented().isEmpty()); - return criteria.serviceTypeName().isEmpty() - && criteria.contractsImplemented().isEmpty() - && criteria.qualifiers().isEmpty(); - } - - static boolean hasValue(String val) { - return (val != null) && !val.isBlank(); - } -} diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfiguredServiceProvider.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfiguredServiceProvider.java deleted file mode 100644 index 90c65b02831..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/ConfiguredServiceProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.runtime; - -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.configdriven.api.ConfigBeanFactory; -import io.helidon.inject.configdriven.api.NamedInstance; - -/** - * An extension to {@link ServiceProvider} that represents a config-driven service. - * - * @param the type of this service provider manages - * @param the type of config beans that this service is configured by - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ConfiguredServiceProvider extends ServiceProvider, ConfigBeanFactory { - - /** - * Returns the config bean associated with this managed service provider. - * - * @return the config bean associated with this managed service provider - * @throws java.lang.NullPointerException if this is the root provider - */ - CB configBean(); - - /** - * Register a named config bean as a child of this root provider. - * - * @param configBean config bean that drives an instance - */ - void registerConfigBean(NamedInstance configBean); -} diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/NameComparator.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/NameComparator.java deleted file mode 100644 index 5fcb431eb2d..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/NameComparator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.runtime; - -import java.util.Comparator; - -import io.helidon.inject.configdriven.api.NamedInstance; - -/** - * Comparator of config bean names, {@value NamedInstance#DEFAULT_NAME} is always first. - */ -class NameComparator implements Comparator { - private static final NameComparator INSTANCE = new NameComparator(); - - static Comparator instance() { - return INSTANCE; - } - - @Override - public int compare(String str1, String str2) { - int result = str1.compareTo(str2); - - if (result == 0) { - return result; - } - // @default is desired to be first in the list - if (NamedInstance.DEFAULT_NAME.equals(str1)) { - return -1; - } else if (NamedInstance.DEFAULT_NAME.equals(str2)) { - return 1; - } - - return result; - } -} diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/UnconfiguredServiceProvider.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/UnconfiguredServiceProvider.java deleted file mode 100644 index 951af90e486..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/UnconfiguredServiceProvider.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.runtime; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -import io.helidon.common.config.Config; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceProviderBindable; -import io.helidon.inject.configdriven.api.NamedInstance; -import io.helidon.inject.runtime.HelidonInjectionPlan; - -/** - * Used by root service providers when there are no services that have been configured. - * - * @param the service type - * @param the config bean type - */ -class UnconfiguredServiceProvider extends ConfigDrivenServiceProviderBase { - private final ConfigDrivenServiceProviderBase delegate; - - /** - * Default Constructor. - * - * @param delegate the root delegate - */ - UnconfiguredServiceProvider(ConfigDrivenServiceProviderBase delegate) { - super(delegate.instanceId()); - assert (delegate.isRootProvider()); - this.delegate = Objects.requireNonNull(delegate); - rootProvider(delegate); - assert (rootProvider().orElseThrow() == delegate); - } - - @Override - protected Optional maybeActivate(ContextualServiceQuery query) { - return Optional.empty(); - } - - @Override - public ServiceInfo serviceInfo() { - return delegate.serviceInfo(); - } - - @Override - public Phase currentActivationPhase() { - return delegate.currentActivationPhase(); - } - - @Override - public DependenciesInfo dependencies() { - return delegate.dependencies(); - } - - @Override - public Optional injectionServices() { - return delegate.injectionServices(); - } - - @Override - protected String identitySuffix() { - return delegate.identitySuffix(); - } - - @Override - public String name(boolean simple) { - return delegate.name(simple); - } - - @Override - public Optional> serviceProviderBindable() { - return delegate.serviceProviderBindable(); - } - - @Override - public boolean isCustom() { - return delegate.isCustom(); - } - - @Override - public boolean isRootProvider() { - return false; - } - - @Override - public Optional first(ContextualServiceQuery query) { - // the entire point of this class is to really ensure that we do not resolve injection points! - return Optional.empty(); - } - - @Override - public Class serviceType() { - return delegate.serviceType(); - } - - @Override - public Map getOrCreateInjectionPlan(boolean resolveIps) { - return super.getOrCreateInjectionPlan(resolveIps); - } - - @Override - public CB configBean() { - throw new NullPointerException("Config bean is not available on root config driven provider."); - } - - @Override - protected boolean drivesActivation() { - return delegate.drivesActivation(); - } - - @Override - protected void doPreDestroying(LogEntryAndResult logEntryAndResult) { - delegate.doPreDestroying(logEntryAndResult); - } - - @Override - protected void doDestroying(LogEntryAndResult logEntryAndResult) { - delegate.doDestroying(logEntryAndResult); - } - - @Override - protected void onFinalShutdown() { - delegate.onFinalShutdown(); - } - - @Override - public List> createConfigBeans(Config config) { - return List.of(); - } - - @Override - public Class configBeanType() { - return delegate.configBeanType(); - } - - @Override - protected ConfigDrivenServiceProviderBase createInstance(NamedInstance configBean) { - return delegate.createInstance(configBean); - } -} diff --git a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/package-info.java b/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/package-info.java deleted file mode 100644 index 8e7c96a276e..00000000000 --- a/inject/configdriven/runtime/src/main/java/io/helidon/inject/configdriven/runtime/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Config-driven Services API. - */ -package io.helidon.inject.configdriven.runtime; diff --git a/inject/configdriven/runtime/src/main/java/module-info.java b/inject/configdriven/runtime/src/main/java/module-info.java deleted file mode 100644 index fe144c86edc..00000000000 --- a/inject/configdriven/runtime/src/main/java/module-info.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import io.helidon.common.features.api.Feature; -import io.helidon.common.features.api.Preview; - -/** - * Injection Config-Driven Services Module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Feature(value = "Config Driven", - since = "4.0.0", - path = {"Inject", "Config Driven"}, - description = "Config Driven Services") -@Preview -module io.helidon.inject.configdriven.runtime { - requires static io.helidon.common.features.api; - requires static io.helidon.config.metadata; - requires static jakarta.annotation; - requires static jakarta.inject; - - requires transitive io.helidon.builder.api; - requires transitive io.helidon.common.types; - requires transitive io.helidon.config; - requires transitive io.helidon.inject.api; - requires transitive io.helidon.inject.configdriven.api; // required for compilation of generated types - requires transitive io.helidon.inject.runtime; - - exports io.helidon.inject.configdriven.runtime; - -} diff --git a/inject/configdriven/tests/config/pom.xml b/inject/configdriven/tests/config/pom.xml deleted file mode 100644 index 5f2897c70e4..00000000000 --- a/inject/configdriven/tests/config/pom.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject.configdriven.tests - helidon-inject-configdriven-tests-project - 4.2.0-SNAPSHOT - - helidon-inject-configdriven-tests-config - Helidon Injection ConfigDriven Tests Config - Test builder with configuration - - - - io.helidon.builder - helidon-builder-api - - - io.helidon.config - helidon-config-metadata - provided - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - jakarta.inject - jakarta.inject-api - provided - - - io.helidon.inject.configdriven - helidon-inject-configdriven-api - - - - io.helidon.inject - helidon-inject-runtime - true - - - - io.helidon.inject.configdriven - helidon-inject-configdriven-runtime - true - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - - diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/EnumRelatedConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/EnumRelatedConfigBlueprint.java deleted file mode 100644 index c0c61e76b8c..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/EnumRelatedConfigBlueprint.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; - -@Prototype.Blueprint -@Configured -interface EnumRelatedConfigBlueprint { - - FakeClientAuth clientAuth(); - - Optional optionalClientAuth(); - - @Option.Singular - List list(); - - @Option.Singular - Set set(); - - @Option.Singular - Map map(); - - enum InlinedEnum { - TEST - } - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeClientAuth.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeClientAuth.java deleted file mode 100644 index 35b87bb7fb4..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeClientAuth.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -/** - * Indicates whether the server requires authentication of tbe client by the certificate. - */ -public enum FakeClientAuth { - - /** - * Authentication is required. - */ - REQUIRE(FakeNettyClientAuth.REQUIRE), - - /** - * Authentication is optional. - */ - OPTIONAL(FakeNettyClientAuth.OPTIONAL), - - /** - * Authentication is not required. - */ - NONE(FakeNettyClientAuth.NONE); - - private final FakeNettyClientAuth clientAuth; - - FakeClientAuth(FakeNettyClientAuth clientAuth) { - this.clientAuth = clientAuth; - } - - FakeNettyClientAuth nettyClientAuth() { - return clientAuth; - } - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeComponentTracingConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeComponentTracingConfigBlueprint.java deleted file mode 100644 index feb65db9ec5..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeComponentTracingConfigBlueprint.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Map; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; - -/** - * aka ComponentTracing. - * - * A component is a single "layer" of the application that can trace. - * Component examples: - *
    - *
  • web-server: webServer adds the root tracing span + two additional spans (content-read and content-write)
  • - *
  • security: security adds the overall request security span, a span for authentication ("security:atn"), a span for - * authorization "security:atz", and a span for response processing ("security:response")
  • - *
  • jax-rs: JAX-RS integration adds spans for overall resource invocation
  • - *
- */ -@Prototype.Blueprint -@Configured -interface FakeComponentTracingConfigBlueprint extends FakeTraceableConfigBlueprint { - - // Builder::addSpan(String span, FakeSpanLogTracingConfigBean val), Impl::getSpan(String span), etc. - @Option.Singular("span") - Map spanLogMap(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeKeyConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeKeyConfigBlueprint.java deleted file mode 100644 index 1f9b68293db..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeKeyConfigBlueprint.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.Optional; - -import io.helidon.builder.api.Prototype; - -/** - * aka KeyConfig. - * - */ -@Prototype.Blueprint -interface FakeKeyConfigBlueprint { - - /** - * The public key of this config if configured. - * - * @return the public key of this config or empty if not configured - */ - Optional publicKey(); - - /** - * The private key of this config if configured. - * - * @return the private key of this config or empty if not configured - */ - Optional privateKey(); - - /** - * The public X.509 Certificate if configured. - * - * @return the public certificate of this config or empty if not configured - */ - Optional publicCert(); - - /** - * The X.509 Certificate Chain. - * - * @return the certificate chain or empty list if not configured - */ - List certChain(); - - /** - * The X.509 Certificates. - * - * @return the certificates configured or empty list if none configured - */ - List certs(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeKeystoreConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeKeystoreConfigBlueprint.java deleted file mode 100644 index d9aa7fed483..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeKeystoreConfigBlueprint.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.List; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * aka KeyConfig.Keystore.Builder - * - * This is a ConfigBean since it marries up to the backing config. - */ -@Configured -@Prototype.Blueprint -interface FakeKeystoreConfigBlueprint { - - String DEFAULT_KEYSTORE_TYPE = "PKCS12"; - - @ConfiguredOption(key = "trust-store") - boolean trustStore(); - - @ConfiguredOption(key = "type", value = DEFAULT_KEYSTORE_TYPE) - String keystoreType(); - - @ConfiguredOption(key = "passphrase") - char[] keystorePassphrase(); - - @ConfiguredOption(key = "key.alias", value = "1") - String keyAlias(); - - @ConfiguredOption(key = "key.passphrase") - char[] keyPassphrase(); - - @ConfiguredOption(key = "cert.alias") - @Option.Singular("certAlias") - List certAliases(); - - @ConfiguredOption(key = "cert-chain.alias") - String certChainAlias(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeNettyClientAuth.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeNettyClientAuth.java deleted file mode 100644 index 71c0ab2e620..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeNettyClientAuth.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -public enum FakeNettyClientAuth { - NONE, - OPTIONAL, - REQUIRE; - - FakeNettyClientAuth() { - } -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakePathTracingConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakePathTracingConfigBlueprint.java deleted file mode 100644 index 9d24a065241..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakePathTracingConfigBlueprint.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.List; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * aka PathTracing. - * - * Traced system configuration for web server for a specific path. - */ -@Configured -@Prototype.Blueprint -interface FakePathTracingConfigBlueprint { - - /** - * Path this configuration should configure. - * - * @return path on the web server - */ - String path(); - - /** - * Method(s) this configuration should be valid for. This can be used to restrict the configuration - * only to specific HTTP methods (such as {@code GET} or {@code POST}). - * - * @return list of methods, if empty, this configuration is valid for any method - */ - @Option.Singular("method") - // Builder::addMethod(String method); - List methods(); - - @ConfiguredOption(required = true) - FakeTracingConfig tracedConfig(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeRoutingConfig.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeRoutingConfig.java deleted file mode 100644 index 6bc24da01b3..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeRoutingConfig.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -/** - * aka Routing. - */ -public interface FakeRoutingConfig extends FakeServerLifecycle { - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeServerConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeServerConfigBlueprint.java deleted file mode 100644 index 50f38e83fdd..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeServerConfigBlueprint.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.time.Duration; -import java.util.Map; -import java.util.Optional; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * aka ServerConfiguration. - */ -@Prototype.Blueprint -@Configured(root = true, prefix = "server") -interface FakeServerConfigBlueprint extends FakeSocketConfigBlueprint { - - /** - * Returns the count of threads in the pool used to process HTTP requests. - *

- * Default value is {@link Runtime#availableProcessors()}. - * - * @return a workers count - */ - Optional workersCount(); - - /** - * A socket configuration of an additional named server socket. - *

- * An additional named server socket may have a dedicated {@link FakeRoutingConfig} configured - * - * @param name the name of the additional server socket - * @return an additional named server socket configuration or {@code empty} if there is no such - * named server socket configured - */ - default Optional namedSocket(String name) { - return Optional.ofNullable(sockets().get(name)); - } - - // - // the socketList, socketSet, and sockets are sharing the same config key. This is atypical but here to ensure that the - // underlying builder machinery can handle these variants. We need to ensure that the attribute names do not clash, however, - // which is why we've used @Singular to disambiguate the attribute names where necessary. - // - - /** - * A map of all the configured server sockets; that is the default server socket. - * - * @return a map of all the configured server sockets, never null - */ - @Option.Singular("socket") // note that singular names cannot clash - @ConfiguredOption(key = "sockets") - Map sockets(); - - /** - * The maximum amount of time that the server will wait to shut - * down regardless of the value of any additionally requested - * quiet period. - * - *

The default implementation of this method returns {@link - * java.time.Duration#ofSeconds(long) Duration.ofSeconds(10L)}.

- * - * @return the {@link java.time.Duration} to use - */ - @ConfiguredOption(key = "whatever") - default Duration maxShutdownTimeout() { - return Duration.ofSeconds(10L); - } - - /** - * The quiet period during which the webserver will wait for new - * incoming connections after it has been told to shut down. - * - *

The webserver will wait no longer than the duration returned - * by the {@link #maxShutdownTimeout()} method.

- * - *

The default implementation of this method returns {@link - * java.time.Duration#ofSeconds(long) Duration.ofSeconds(0L)}, indicating - * that there will be no quiet period.

- * - * @return the {@link java.time.Duration} to use - */ - default Duration shutdownQuietPeriod() { - return Duration.ofSeconds(0L); - } - - /** - * Whether to print details of HelidonFeatures. - * - * @return whether to print details - */ - @ConfiguredOption("false") - boolean printFeatureDetails(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeServerLifecycle.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeServerLifecycle.java deleted file mode 100644 index 5fa14369902..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeServerLifecycle.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -/** - * aka ServerLifecycle. - * Basic server lifecycle operations. - */ -public interface FakeServerLifecycle { - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSocketConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSocketConfigBlueprint.java deleted file mode 100644 index 7307397b26d..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSocketConfigBlueprint.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * aka ServerConfiguration. - * The SocketConfiguration configures a port to listen on and its associated server socket parameters. - */ -@Configured -@Prototype.Blueprint -interface FakeSocketConfigBlueprint { - - /** - * The default backlog size to configure the server sockets with if no other value - * is provided. - */ - int DEFAULT_BACKLOG_SIZE = 1024; - - /** - * Name of this socket. - * Default to WebServer#DEFAULT_SOCKET_NAME for the main and - * default server socket. All other sockets must be named. - * - * @return name of this socket - */ - @ConfiguredOption("@default") - String name(); - - /** - * Returns a server port to listen on with the server socket. If port is - * {@code 0} then any available ephemeral port will be used. - * - * @return the server port of the server socket - */ - @ConfiguredOption("0") - int port(); - - @ConfiguredOption - Optional bindAddress(); - - /** - * Returns a maximum length of the queue of incoming connections on the server - * socket. - *

- * Default value is {@link #DEFAULT_BACKLOG_SIZE}. - * - * @return a maximum length of the queue of incoming connections - */ - @ConfiguredOption("1024") - int backlog(); - - /** - * Returns a server socket timeout in milliseconds or {@code 0} for an infinite timeout. - * - * @return a server socket timeout in milliseconds or {@code 0} - */ - @ConfiguredOption("0") - int timeoutMillis(); - - /** - * Returns proposed value of the TCP receive window that is advertised to the remote peer on the - * server socket. - *

- * If {@code 0} then use implementation default. - * - * @return a buffer size in bytes of the server socket or {@code 0} - */ - @ConfiguredOption("0") - int receiveBufferSize(); - - /** - * Return a {@link FakeWebServerTlsConfig} containing server TLS configuration - * . When empty {@link java.util.Optional} is returned - * no TLS should be configured. - * - * @return web server tls configuration - */ - @ConfiguredOption - Optional tls(); - - /** - * Whether this socket is enabled (and will be opened on server startup), or disabled - * (and ignored on server startup). - * - * @return {@code true} for enabled socket, {@code false} for socket that should not be opened - */ - @ConfiguredOption("true") - boolean enabled(); - - /** - * Maximal size of all headers combined. - * - * @return size in bytes - */ - @ConfiguredOption("8192") - int maxHeaderSize(); - - /** - * Maximal length of the initial HTTP line. - * - * @return length - */ - @ConfiguredOption("4096") - int maxInitialLineLength(); - - /** - * Maximum size allowed for an HTTP payload in a client request. A negative - * value indicates that there is no maximum set. - * - * @return maximum payload size - */ - @ConfiguredOption("-1") - long maxPayloadSize(); - - /** - * Maximum length of the content of an upgrade request. - * - * @return maximum length of the content of an upgrade request - */ - @ConfiguredOption("65536") - int maxUpgradeContentLength(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSpanLogTracingConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSpanLogTracingConfigBlueprint.java deleted file mode 100644 index 58a1374d5f8..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSpanLogTracingConfigBlueprint.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; - -/** - * aka SpanLogTracingConfig. - * Configuration of a single log event in a traced span. - */ -@Prototype.Blueprint -@Configured -interface FakeSpanLogTracingConfigBlueprint extends FakeTraceableConfigBlueprint { - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSpanTracingConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSpanTracingConfigBlueprint.java deleted file mode 100644 index 1a04ab7945c..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeSpanTracingConfigBlueprint.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Map; -import java.util.Optional; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * aka SpanTracingConfig. - * - * Configuration of a single traced span. - */ -@Prototype.Blueprint -@Configured -interface FakeSpanTracingConfigBlueprint extends FakeTraceableConfigBlueprint { - - /** - * When rename is desired, returns the new name. - * - * @return new name for this span or empty when rename is not desired - */ - @ConfiguredOption - Optional newName(); - - @ConfiguredOption - @Option.Singular("spanLog") - // B addSpanLog(String, FakeSpanLogTracingConfigBean); - Map spanLogMap(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTlsWSNotDrivenByCB.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTlsWSNotDrivenByCB.java deleted file mode 100644 index 07c41ae6e42..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTlsWSNotDrivenByCB.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Objects; - -import io.helidon.inject.configdriven.api.ConfigDriven; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; -import jakarta.inject.Named; - -@ConfigDriven(value = FakeWebServerTlsConfigBlueprint.class, activateByDefault = true) -@Named("jimmy") -public class FakeTlsWSNotDrivenByCB { - - private final FakeWebServerTlsConfig cfg; - private boolean running; - - @Inject - FakeTlsWSNotDrivenByCB(FakeWebServerTlsConfig cfg) { - this.cfg = Objects.requireNonNull(cfg); - } - - /** - * For Testing. - */ - @PostConstruct - public void initialize() { - assert (!running); - running = true; - } - - /** - * For Testing. - */ - @PreDestroy - public void shutdown() { - running = false; - } - - public FakeWebServerTlsConfig configuration() { - return cfg; - } - - public boolean isRunning() { - return running; - } - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTraceableConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTraceableConfigBlueprint.java deleted file mode 100644 index 82a4e0ccfb1..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTraceableConfigBlueprint.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; - -/** - * aka Traceable. - * Tracing configuration that can be enabled or disabled. - */ -@Configured -@Prototype.Blueprint -interface FakeTraceableConfigBlueprint { - /** - * Whether this trace should be executed or not. - * - * @return {@code true} if span/component should be traced, - * {@code false} if it should not, - * {@code empty} when this flag is not explicitly configured - */ - Optional isEnabled(); - - /** - * Name of this traceable unit. - * - * @return name - */ - String name(); - - /** - * Whether this traceable should be executed or not. - * - * @return {@code true} if span/component should be traced, - * {@code false} if it should not - */ - default boolean enabled() { - return isEnabled().orElse(true); - } - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTracer.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTracer.java deleted file mode 100644 index 7eba63c65fa..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTracer.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -/** - * Tracer abstraction. - * Tracer is the central point that collects tracing spans, and (probably) pushes them to backend. - */ -public interface FakeTracer { - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTracingConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTracingConfigBlueprint.java deleted file mode 100644 index 336b355e8b6..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeTracingConfigBlueprint.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Map; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; - -/** - * aka TracingConfig. - *

- * Tracing configuration that contains traced components (such as WebServer, Security) and their traced spans and span logs. - * Spans can be renamed through configuration, components, spans and span logs may be disabled through this configuration. - */ -@Configured(prefix = "tracing", root = true) -@Prototype.Blueprint -interface FakeTracingConfigBlueprint extends FakeTraceableConfigBlueprint { - - // Builder::addComponent(String component); Impl::getComponent(String component); - @Option.Singular - Map components(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServer.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServer.java deleted file mode 100644 index a6d4ef0dba1..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Objects; -import java.util.Optional; - -import io.helidon.inject.configdriven.api.ConfigDriven; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; - -/** - * For Testing. - */ -@ConfigDriven(value = FakeServerConfigBlueprint.class, activateByDefault = true) -public class FakeWebServer implements FakeWebServerContract { - - private final FakeServerConfig cfg; - private boolean running; - - @Inject - FakeWebServer(FakeServerConfig cfg, - Optional tracer) { - this.cfg = Objects.requireNonNull(cfg); - assert (tracer.isEmpty()); - } - - /** - * For Testing. - */ - @PostConstruct - public void initialize() { - assert (!running); - running = true; - } - - /** - * For Testing. - */ - @PreDestroy - public void shutdown() { - running = false; - } - - @Override - public FakeServerConfig configuration() { - return cfg; - } - - @Override - public boolean isRunning() { - return running; - } - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerContract.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerContract.java deleted file mode 100644 index 618453903a3..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerContract.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import io.helidon.inject.api.Contract; - -/** - * For Testing. - */ -@Contract -public interface FakeWebServerContract { - - /** - * Gets effective server configuration. - * - * @return Server configuration - */ - FakeServerConfig configuration(); - - /** - * Returns {@code true} if the server is currently running. Running server in stopping phase returns {@code true} until it - * is not fully stopped. - * - * @return {@code true} if server is running - */ - boolean isRunning(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerNotDrivenAndHavingConfiguredByOverrides.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerNotDrivenAndHavingConfiguredByOverrides.java deleted file mode 100644 index 9d6bbb7bd4b..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerNotDrivenAndHavingConfiguredByOverrides.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Optional; - -import io.helidon.inject.configdriven.api.ConfigDriven; - -import jakarta.inject.Inject; - -@ConfigDriven(FakeServerConfigBlueprint.class) -public class FakeWebServerNotDrivenAndHavingConfiguredByOverrides extends FakeWebServer { - - @Inject - FakeWebServerNotDrivenAndHavingConfiguredByOverrides(FakeServerConfig cfg, - Optional tracer) { - super(cfg, tracer); - } - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerTlsConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerTlsConfigBlueprint.java deleted file mode 100644 index e71151a646d..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/FakeWebServerTlsConfigBlueprint.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.security.SecureRandom; -import java.util.List; -import java.util.Optional; -import java.util.Random; -import java.util.Set; - -import javax.net.ssl.SSLContext; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.LazyValue; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.inject.configdriven.api.ConfigBean; - -/** - * aka WebServerTls. - * - * A class wrapping transport layer security (TLS) configuration for - * WebServer sockets. - */ -@ConfigBean -@Configured(root = true, prefix = "tls") -@Prototype.Blueprint -interface FakeWebServerTlsConfigBlueprint { - String PROTOCOL = "TLS"; - // secure random cannot be stored in native image, it must be initialized at runtime - LazyValue RANDOM = LazyValue.create(SecureRandom::new); - - /** - * This constant is a context classifier for the x509 client certificate if it is present. Callers may use this - * constant to lookup the client certificate associated with the current request context. - */ - String CLIENT_X509_CERTIFICATE = FakeWebServerTlsConfigBlueprint.class.getName() + ".client-x509-certificate"; - - @ConfiguredOption - Set enabledTlsProtocols(); - - // TODO: had to make this Optional - we might need something like 'ExternalConfigBean' for this case ? - Optional sslContext(); - - @Option.Singular("cipher") - @ConfiguredOption(key = "cipher") - // Set cipherSuite(); - List cipherSuite(); - - /** - * Whether this TLS config has security enabled (and the socket is going to be - * protected by one of the TLS protocols), or no (and the socket is going to be plain). - * - * @return {@code true} if this configuration represents a TLS configuration, {@code false} for plain configuration - */ - @ConfiguredOption("false") - boolean enabled(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/SSLContextConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/SSLContextConfigBlueprint.java deleted file mode 100644 index e74e548afa5..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/SSLContextConfigBlueprint.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Random; - -import io.helidon.builder.api.Prototype; - -/** - * aka SSLContextBuilder. - * Note that this is just a normal builder, and will not be integrated with Config. - * Builder for configuring a new SslContext for creation. - */ -@Prototype.Blueprint -interface SSLContextConfigBlueprint { - - String PROTOCOL = "TLS"; - Random RANDOM = new Random(); - - FakeKeyConfig privateKeyConfig(); - - FakeKeyConfig trustConfig(); - - long sessionCacheSize(); - - long sessionTimeout(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestClientConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestClientConfigBlueprint.java deleted file mode 100644 index 6ddf5e55e69..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestClientConfigBlueprint.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Map; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.inject.configdriven.api.ConfigBean; - -/** - * For testing purpose. - */ -@ConfigBean(repeatable = true) -@Configured(root = true) -@Prototype.Blueprint -interface TestClientConfigBlueprint extends TestCommonConfigBlueprint { - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption("default") - @Override - String name(); - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption("0") - int serverPort(); - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption - Map headers(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestCommonConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestCommonConfigBlueprint.java deleted file mode 100644 index 8e63a9783c2..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestCommonConfigBlueprint.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.List; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * For testing purpose. - */ -@Configured -@Prototype.Blueprint -interface TestCommonConfigBlueprint { - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption - String name(); - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption(required = true) - int port(); - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption - List cipherSuites(); - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption("") - char[] pswd(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestServerConfigBlueprint.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestServerConfigBlueprint.java deleted file mode 100644 index 32b15f7c719..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/TestServerConfigBlueprint.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.inject.configdriven.api.ConfigBean; - -/** - * For testing purpose. - */ -@ConfigBean(atLeastOne = true) -@Prototype.Blueprint -@Configured(root = true) -interface TestServerConfigBlueprint extends TestCommonConfigBlueprint { - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption("default") - @Override - String name(); - - /** - * For testing purpose. - * - * @return for testing purposes - */ - @ConfiguredOption - Optional description(); - -} diff --git a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/package-info.java b/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/package-info.java deleted file mode 100644 index 9432cafeee9..00000000000 --- a/inject/configdriven/tests/config/src/main/java/io/helidon/inject/configdriven/tests/config/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ConfigBean test subjects. - */ -package io.helidon.inject.configdriven.tests.config; diff --git a/inject/configdriven/tests/config/src/main/java/module-info.java b/inject/configdriven/tests/config/src/main/java/module-info.java deleted file mode 100644 index 9ed4589a27d..00000000000 --- a/inject/configdriven/tests/config/src/main/java/module-info.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon ConfigBean Builder test Module (i.e., only common config and w/o config-driven services). - */ -module io.helidon.builder.config.tests.test.config { - - requires io.helidon.builder.api; - requires io.helidon.common.config; - requires io.helidon.common; - requires io.helidon.inject.api; - requires io.helidon.inject.configdriven.api; - - requires static io.helidon.config.metadata; - requires static io.helidon.inject.configdriven.runtime; - requires static io.helidon.inject.runtime; - requires static jakarta.annotation; - requires static jakarta.inject; - - exports io.helidon.inject.configdriven.tests.config; - -} diff --git a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/AbstractConfigBeanTest.java b/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/AbstractConfigBeanTest.java deleted file mode 100644 index 39e3e4ad0f5..00000000000 --- a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/AbstractConfigBeanTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Map; - -import io.helidon.config.ConfigSources; -import io.helidon.config.MapConfigSource; - -class AbstractConfigBeanTest { - static final String NESTED = "nested"; - static final String FAKE_SOCKET_CONFIG = "sockets"; - static final String FAKE_SERVER_CONFIG = "fake-server"; - - MapConfigSource.Builder createRootPlusOneSocketTestingConfigSource() { - return ConfigSources.create( - Map.of( - FAKE_SERVER_CONFIG + ".name", "root", - FAKE_SERVER_CONFIG + ".port", "8080", - FAKE_SERVER_CONFIG + "." + FAKE_SOCKET_CONFIG + ".1.name", "first", - FAKE_SERVER_CONFIG + "." + FAKE_SOCKET_CONFIG + ".1.port", "8081" - ), "config-nested-plus-one-socket"); - } - - MapConfigSource.Builder createNestedPlusOneSocketAndOneTlsTestingConfigSource() { - return ConfigSources.create( - Map.of( - NESTED + "." + FAKE_SERVER_CONFIG + ".name", "nested", - NESTED + "." + FAKE_SERVER_CONFIG + ".port", "8080", - NESTED + "." + FAKE_SERVER_CONFIG + ".worker-count", "2", - NESTED + "." + FAKE_SERVER_CONFIG + "." + FAKE_SOCKET_CONFIG + ".1.name", "first", - NESTED + "." + FAKE_SERVER_CONFIG + "." + FAKE_SOCKET_CONFIG + ".1.port", "8081", - NESTED + "." + FAKE_SERVER_CONFIG + "." + FAKE_SOCKET_CONFIG + ".1.tls.enabled", "true", - NESTED + "." + FAKE_SERVER_CONFIG + "." + FAKE_SOCKET_CONFIG + ".1.tls.cipher.0", "cipher-1", - NESTED + "." + FAKE_SERVER_CONFIG + "." + FAKE_SOCKET_CONFIG + ".1.tls.enabled-tls-protocols.0", - FakeWebServerTlsConfig.PROTOCOL - ), "config-nested-plus-one-socket-and-tls"); - } - -} diff --git a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/BasicConfigBeanTest.java b/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/BasicConfigBeanTest.java deleted file mode 100644 index 5a2555a1a89..00000000000 --- a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/BasicConfigBeanTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.List; -import java.util.Map; - -import io.helidon.common.Errors; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.yaml.YamlConfigParser; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.CoreMatchers.endsWith; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.startsWith; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasEntry; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class BasicConfigBeanTest { - - @Test - void acceptConfig() { - Config cfg = Config.builder( - ConfigSources.create( - Map.of("name", "server", - "port", "8080", - "description", "test", - "pswd", "pwd1", - "cipher-suites.0", "a", - "cipher-suites.1", "b", - "cipher-suites.2", "c", - "headers.0", "header1", - "headers.1", "header2"), - "my-simple-config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - TestServerConfig serverConfig = TestServerConfig.create(cfg); - assertThat(serverConfig.description(), - optionalValue(equalTo("test"))); - assertThat(serverConfig.name(), - equalTo("server")); - assertThat(serverConfig.port(), - equalTo(8080)); - assertThat(new String(serverConfig.pswd()), - equalTo("pwd1")); - assertThat(serverConfig.toString(), - startsWith("TestServerConfig")); - assertThat(serverConfig.cipherSuites(), - contains("a", "b", "c")); - assertThat(serverConfig.toString(), - endsWith("{name=server,port=8080,cipherSuites=[a, b, c],pswd=****}")); - - TestClientConfig clientConfig = TestClientConfig.create(cfg); - assertThat(clientConfig.name(), - equalTo("server")); - assertThat(clientConfig.port(), - equalTo(8080)); - assertThat(new String(clientConfig.pswd()), - equalTo("pwd1")); - assertThat(clientConfig.toString(), - startsWith("TestClientConfig")); - assertThat(clientConfig.cipherSuites(), - contains("a", "b", "c")); - assertThat(clientConfig.headers(), - hasEntry("0", "header1")); - assertThat(clientConfig.headers(), - hasEntry("1", "header2")); - } - - @Test - void emptyConfig() { - Config cfg = Config.create(); - // port is required - assertThrows(Errors.ErrorMessagesException.class, () -> TestServerConfig.create(cfg)); - } - - @Test - void onlyRequiredConfig() { - Config cfg = Config.create(ConfigSources.create(Map.of("port", "8080"))); - TestServerConfig serverConfig = TestServerConfig.create(cfg); - assertThat(serverConfig.description(), - optionalEmpty()); - assertThat(serverConfig.name(), - equalTo("default")); - assertThat(serverConfig.port(), - equalTo(8080)); - } - - /** - * Callers can conceptually use config beans as just plain old vanilla builders, void of any config usage. - */ - @Test - void noConfig() { - TestServerConfig serverConfig = TestServerConfig.builder() - .port(0) // explicitly set as required - must be set - .build(); - assertThat(serverConfig.description(), optionalEmpty()); - assertThat(serverConfig.name(), - equalTo("default")); - assertThat(serverConfig.port(), - equalTo(0)); - assertThat(serverConfig.cipherSuites(), - equalTo(List.of())); - - serverConfig = TestServerConfig.builder(serverConfig).port(123).build(); - assertThat(serverConfig.description(), - optionalEmpty()); - assertThat(serverConfig.name(), - equalTo("default")); - assertThat(serverConfig.port(), - equalTo(123)); - assertThat(serverConfig.cipherSuites(), - equalTo(List.of())); - - TestClientConfig clientConfig = TestClientConfig.builder() - .port(0) // explicitly set as required - must be set - .build(); - assertThat(clientConfig.name(), - equalTo("default")); - assertThat(clientConfig.port(), - equalTo(0)); - assertThat(clientConfig.headers(), - equalTo(Map.of())); - assertThat(clientConfig.cipherSuites(), - equalTo(List.of())); - - clientConfig = TestClientConfig.builder(clientConfig).port(123).build(); - assertThat(clientConfig.name(), - equalTo("default")); - assertThat(clientConfig.port(), - equalTo(123)); - assertThat(clientConfig.headers(), - equalTo(Map.of())); - assertThat(clientConfig.cipherSuites(), - equalTo(List.of())); - } - - @Test - void equality() { - Config cfg = Config.builder() - .sources(ConfigSources.classpath("io/helidon/builder/config/test/basic-config-bean-test.yaml")) - .addParser(YamlConfigParser.create()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - Config serverCfg = cfg.get("test-server"); - TestServerConfig.Builder serverConfigBeanManualBuilder = TestServerConfig.builder() - .port(serverCfg.get("port").asInt().get()); - serverCfg.get("name").asString().ifPresent(serverConfigBeanManualBuilder::name); - serverCfg.get("pswd").asString().ifPresent(serverConfigBeanManualBuilder::pswd); - serverCfg.get("description").asString().ifPresent(serverConfigBeanManualBuilder::description); - TestServerConfig serverConfigBeanManual = serverConfigBeanManualBuilder.build(); - - Config clientCfg = cfg.get("test-client"); - TestClientConfig.Builder clientConfigBeanManualBuilder = TestClientConfig.builder() - .port(clientCfg.get("port").asInt().get()) - .serverPort(clientCfg.get("server-port").asInt().get()) - .cipherSuites(clientCfg.get("cipher-suites").asList(String.class).get()) - .headers(clientCfg.get("headers").detach().asMap().get()); - clientCfg.get("name").asString().ifPresent(clientConfigBeanManualBuilder::name); - clientCfg.get("pswd").asString().ifPresent(serverConfigBeanManualBuilder::pswd); - TestClientConfig clientConfigBeanManual = clientConfigBeanManualBuilder.build(); - - // juxtaposed to the new ConfigBean approach - TestServerConfig serverConfigBean = TestServerConfig.create(serverCfg); - TestClientConfig clientConfigBean = TestClientConfig.create(clientCfg); - - assertThat(serverConfigBeanManual, equalTo(serverConfigBean)); - assertThat(clientConfigBeanManual, equalTo(clientConfigBean)); - } - -} diff --git a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/EnumRelatedConfigBeanTest.java b/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/EnumRelatedConfigBeanTest.java deleted file mode 100644 index aab72eb3938..00000000000 --- a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/EnumRelatedConfigBeanTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.List; -import java.util.Set; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasEntry; - -class EnumRelatedConfigBeanTest { - - @Test - void testIt() { - EnumRelatedConfig cfg = EnumRelatedConfig.builder() - .clientAuth(FakeClientAuth.OPTIONAL) - .list(List.of(EnumRelatedConfig.InlinedEnum.TEST)) - .addSet(Set.of(EnumRelatedConfig.InlinedEnum.TEST)) - .putMap("test", EnumRelatedConfig.InlinedEnum.TEST) - .build(); - - assertThat(cfg.clientAuth(), - equalTo(FakeClientAuth.OPTIONAL)); - assertThat(cfg.optionalClientAuth(), - optionalEmpty()); - assertThat(cfg.set(), - contains(EnumRelatedConfig.InlinedEnum.TEST)); - assertThat(cfg.list(), - contains(EnumRelatedConfig.InlinedEnum.TEST)); - assertThat(cfg.map(), - hasEntry("test", EnumRelatedConfig.InlinedEnum.TEST)); - } - -} diff --git a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/NestedConfigBeanTest.java b/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/NestedConfigBeanTest.java deleted file mode 100644 index 20b47f34ac5..00000000000 --- a/inject/configdriven/tests/config/src/test/java/io/helidon/inject/configdriven/tests/config/NestedConfigBeanTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.tests.config; - -import java.util.Collection; -import java.util.Objects; - -import io.helidon.common.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.yaml.YamlConfigParser; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.collection.IsMapContaining.hasEntry; - -class NestedConfigBeanTest extends AbstractConfigBeanTest { - - @Test - void rootServerConfigPlusOneSocket() { - Config cfg = io.helidon.config.Config.builder(createRootPlusOneSocketTestingConfigSource()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - FakeServerConfig serverConfig = FakeServerConfig.create(cfg.get(FAKE_SERVER_CONFIG)); - - assertThat(serverConfig.name(), - equalTo("root")); - assertThat(serverConfig.port(), - equalTo(8080)); - - // validate the map - assertThat(serverConfig.sockets(), - hasEntry("first", - FakeSocketConfig.builder() - .name("first") - .port(8081) - .build())); - assertThat(serverConfig.sockets().get("first").tls(), - optionalEmpty()); - } - - @Test - void nestedServerConfigPlusOneSocketAndOneTls() { - Config cfg = io.helidon.config.Config.builder(createNestedPlusOneSocketAndOneTlsTestingConfigSource()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - FakeServerConfig serverConfig = FakeServerConfig.create(cfg.get(NESTED + "." + FAKE_SERVER_CONFIG)); - - assertThat(serverConfig.name(), - equalTo("nested")); - assertThat(serverConfig.port(), - equalTo(8080)); - - // validate the map - FakeWebServerTlsConfig tls = serverConfig.sockets().get("first").tls().orElseThrow(); - assertThat(tls.enabled(), - is(true)); - assertThat(tls.cipherSuite(), - containsInAnyOrder("cipher-1")); - assertThat(tls.enabledTlsProtocols(), - containsInAnyOrder(FakeWebServerTlsConfig.PROTOCOL)); - } - - @Test - void fakeServerConfigFromUnnamedYaml() { - Config cfg = io.helidon.config.Config.builder() - .sources(ConfigSources.classpath("io/helidon/builder/config/test/FakeServerConfigPlusTwoUnnamedSockets.yaml")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - FakeServerConfig serverConfig = FakeServerConfig.create(cfg.get(FAKE_SERVER_CONFIG)); - - assertThat(serverConfig.name(), - equalTo("@default")); - - // validate the map - FakeSocketConfig zero = Objects.requireNonNull(serverConfig.namedSocket("0").orElse(null), - serverConfig.sockets().toString()); - assertThat(zero.bindAddress(), optionalValue(is("127.0.0.1"))); - assertThat(zero.port(), - equalTo(8086)); - assertThat(zero.tls(), - optionalEmpty()); - FakeSocketConfig one = Objects.requireNonNull(serverConfig.sockets().get("1"), - serverConfig.sockets().toString()); - assertThat(one.bindAddress(), - optionalValue(is("localhost"))); - assertThat(one.port(), - equalTo(8087)); - FakeWebServerTlsConfig tls = one.tls().orElseThrow(); - assertThat(tls.enabled(), - is(true)); - assertThat(tls.cipherSuite(), - containsInAnyOrder("cipher-1")); - assertThat(tls.enabledTlsProtocols(), - containsInAnyOrder(FakeWebServerTlsConfig.PROTOCOL)); - - Collection values = serverConfig.sockets().values(); - // validate the list - assertThat(values, - contains(FakeSocketConfig.builder() - .bindAddress("127.0.0.1") - .port(8086) - .build(), - FakeSocketConfig.builder() - .bindAddress("localhost") - .port(8087) - .tls(tls) - .build())); - } - - @Test - void fakeServerConfigFromNamedYaml() { - Config cfg = io.helidon.config.Config.builder() - .sources(ConfigSources.classpath("io/helidon/builder/config/test/FakeServerConfigPlusTwoNamedSockets.yaml")) - .addParser(YamlConfigParser.create()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - FakeServerConfig serverConfig = FakeServerConfig.create(cfg.get(FAKE_SERVER_CONFIG)); - - // validate the map - assertThat(serverConfig.name(), - equalTo("@default")); - FakeSocketConfig admin = serverConfig.namedSocket("admin").orElseThrow(); - assertThat(admin.port(), - equalTo(8086)); - assertThat(admin.name(), - equalTo("admin")); - - // the name is always taken from the values, even if not the same as the name from object config node - FakeSocketConfig secure = serverConfig.namedSocket("obscure").orElseThrow(); - assertThat(secure.port(), - equalTo(8087)); - assertThat(secure.name(), - equalTo("obscure")); - FakeWebServerTlsConfig tls = secure.tls().orElseThrow(); - assertThat(tls.enabled(), - is(true)); - assertThat(tls.cipherSuite(), - containsInAnyOrder("cipher-1")); - assertThat(tls.enabledTlsProtocols(), - containsInAnyOrder(FakeWebServerTlsConfig.PROTOCOL)); - } - -} diff --git a/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/FakeServerConfigPlusTwoNamedSockets.yaml b/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/FakeServerConfigPlusTwoNamedSockets.yaml deleted file mode 100644 index dfced8379bb..00000000000 --- a/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/FakeServerConfigPlusTwoNamedSockets.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -fake-server: - sockets: - admin: - name: "admin" - bind-address: "127.0.0.1" - port: 8086 - secure: - name: "obscure" - bind-address: "localhost" - port: 8087 - tls: - enabled: true - cipher: "cipher-1" - enabled-tls-protocols: "TLS" diff --git a/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/FakeServerConfigPlusTwoUnnamedSockets.yaml b/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/FakeServerConfigPlusTwoUnnamedSockets.yaml deleted file mode 100644 index 8d3147c7f3f..00000000000 --- a/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/FakeServerConfigPlusTwoUnnamedSockets.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -fake-server: - sockets: - - bind-address: "127.0.0.1" - port: 8086 - - bind-address: "localhost" - port: 8087 - tls: - enabled: true - cipher: "cipher-1" - enabled-tls-protocols: "TLS" diff --git a/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/basic-config-bean-test.yaml b/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/basic-config-bean-test.yaml deleted file mode 100644 index 699722ab122..00000000000 --- a/inject/configdriven/tests/config/src/test/resources/io/helidon/builder/config/test/basic-config-bean-test.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -test-server: - name: "server" - bind-address: "127.0.0.1" -# pswd: "no-pswd" - port: 8086 -# description: "an optional description" - -test-client: - port: 8087 - server-port: 8086 -# pswd: "no-pswd" - cipher-suites: - - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" - - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" - headers: - header-key1: "header-val1" - header-key2: "header-val2" diff --git a/inject/configdriven/tests/configuredby-application/README.md b/inject/configdriven/tests/configuredby-application/README.md deleted file mode 100644 index 5b0e7930f67..00000000000 --- a/inject/configdriven/tests/configuredby-application/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# inject-configdriven-test-configuredby-application - -Tests for full ConfiguredBy-generated service types, in combination with the DI model calculated at compile time using the inject-maven-plugin instead of calculated at runtime as is the case with inject-configdriven-test-configuredby. diff --git a/inject/configdriven/tests/configuredby-application/pom.xml b/inject/configdriven/tests/configuredby-application/pom.xml deleted file mode 100644 index a1d77aa3441..00000000000 --- a/inject/configdriven/tests/configuredby-application/pom.xml +++ /dev/null @@ -1,177 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject.configdriven.tests - helidon-inject-configdriven-tests-project - 4.2.0-SNAPSHOT - - helidon-inject-configdriven-tests-configuredby-application - Helidon Injection ConfigDriven Tests CfgedBy App - - The same tests as test-configuredby, but instead using the maven application generation - in order to compute di plan at compile-time - - - - true - true - true - false - true - true - true - - - - - io.helidon.inject.configdriven - helidon-inject-configdriven-runtime - - - io.helidon.inject.configdriven.tests - helidon-inject-configdriven-tests-configuredby - ${helidon.version} - - - jakarta.inject - jakarta.inject-api - provided - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - io.helidon.inject - helidon-inject-testing - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - alphabetical - - - - org.apache.maven.plugins - maven-compiler-plugin - - - -Ainject.debug=${inject.debug} - -Ainject.application.pre.create=true - -Ainject.mapApplicationToSingletonScope=true - - true - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - ${helidon.version} - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - io.helidon.inject - helidon-inject-maven-plugin - ${helidon.version} - - - compile - compile - - application-create - - - - - - - - - - - - - - -Ainject.debug=${inject.debug} - -Ainject.autoAddNonContractInterfaces=true - -Ainject.application.pre.create=true - - NAMED - - - - - - - - diff --git a/inject/configdriven/tests/configuredby-application/src/main/java/io/helidon/inject/configdriven/configuredby/application/test/ASimpleRunLevelService.java b/inject/configdriven/tests/configuredby-application/src/main/java/io/helidon/inject/configdriven/configuredby/application/test/ASimpleRunLevelService.java deleted file mode 100644 index badd7ad8b28..00000000000 --- a/inject/configdriven/tests/configuredby-application/src/main/java/io/helidon/inject/configdriven/configuredby/application/test/ASimpleRunLevelService.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.application.test; - -import java.util.List; -import java.util.Objects; - -import io.helidon.inject.api.Resettable; -import io.helidon.inject.api.RunLevel; -import io.helidon.inject.configdriven.configuredby.test.ASingletonServiceContract; -import io.helidon.inject.configdriven.tests.config.FakeWebServerContract; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@Singleton -@RunLevel(RunLevel.STARTUP) -public class ASimpleRunLevelService implements Resettable { - - static int postConstructCount; - static int preDestroyCount; - private boolean running; - private ASingletonServiceContract singleton; - private List> fakeWebServers; - - @Inject // testing an empty/void ctor here - public ASimpleRunLevelService() { - } - - public static int getPostConstructCount() { - return postConstructCount; - } - - public static int getPreDestroyCount() { - return preDestroyCount; - } - - @Inject - void setSingleton(ASingletonServiceContract singleton) { - assert (this.singleton == null); - this.singleton = Objects.requireNonNull(singleton); - } - - @Inject - void setWebServer(List> fakeWebServers) { - assert (this.fakeWebServers == null); - assert (!Objects.requireNonNull(fakeWebServers).isEmpty()); - this.fakeWebServers = Objects.requireNonNull(fakeWebServers); - } - - @Override - public boolean reset(boolean deep) { - postConstructCount = 0; - preDestroyCount = 0; - return true; - } - - @PostConstruct - public void postConstruct() { - assert (!running); - Objects.requireNonNull(singleton); - Objects.requireNonNull(fakeWebServers); - running = true; - postConstructCount++; - } - - @PreDestroy - public void preDestroy() { - assert (running); - Objects.requireNonNull(singleton); - Objects.requireNonNull(fakeWebServers); - preDestroyCount++; - running = false; - } - - public boolean isRunning() { - return running; - } - -} diff --git a/inject/configdriven/tests/configuredby-application/src/test/java/io/helidon/inject/configdriven/configuredby/test/ApplicationConfigBeanTest.java b/inject/configdriven/tests/configuredby-application/src/test/java/io/helidon/inject/configdriven/configuredby/test/ApplicationConfigBeanTest.java deleted file mode 100644 index 6755d6afdac..00000000000 --- a/inject/configdriven/tests/configuredby-application/src/test/java/io/helidon/inject/configdriven/configuredby/test/ApplicationConfigBeanTest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -/** - * Designed to re-run the same tests from base, but using the application-created DI model instead. - */ -class ApplicationConfigBeanTest extends AbstractConfigBeanTest { - -} diff --git a/inject/configdriven/tests/configuredby-application/src/test/java/io/helidon/inject/configdriven/configuredby/test/ApplicationConfiguredByTest.java b/inject/configdriven/tests/configuredby-application/src/test/java/io/helidon/inject/configdriven/configuredby/test/ApplicationConfiguredByTest.java deleted file mode 100644 index ce986f48afc..00000000000 --- a/inject/configdriven/tests/configuredby-application/src/test/java/io/helidon/inject/configdriven/configuredby/test/ApplicationConfiguredByTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Metrics; -import io.helidon.inject.api.RunLevel; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.configdriven.configuredby.application.test.ASimpleRunLevelService; - -import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; - -/** - * Designed to re-run the same tests from base, but using the application-created DI model instead. - */ -class ApplicationConfiguredByTest extends AbstractConfiguredByTest { - - /** - * In application mode, we should not have many lookups recorded. - */ - @Test - void verifyMinimalLookups() { - resetWith(io.helidon.config.Config.builder(createBasicTestingConfigSource(), createRootDefault8080TestingConfigSource()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build()); - - Metrics metrics = injectionServices.metrics().orElseThrow(); - Set criteriaSearchLog = injectionServices.lookups().orElseThrow(); - Set contractSearchLog = criteriaSearchLog.stream() - .flatMap(it -> it.contractsImplemented().stream()) - .collect(Collectors.toCollection(LinkedHashSet::new)); - Set servicesSearchLog = criteriaSearchLog.stream() - .flatMap(it -> it.serviceTypeName().stream()) - .collect(Collectors.toCollection(LinkedHashSet::new)); - Set searchLog = new LinkedHashSet<>(contractSearchLog); - searchLog.addAll(servicesSearchLog); - - // we expect three classes of lookups here: - // 1) Any and all config beans (like FakeServerConfig). - // 2) Any *Optional* unknown services (like the FakeTracer). - // 3) Any intercepted service (like ZImpl). - assertThat("Full log: " + searchLog, - searchLog, - containsInAnyOrder( - // config beans are always looked up - TypeName.create("io.helidon.inject.configdriven.tests.config.FakeServerConfig"), - // tracer doesn't really exist, so it is looked up out of best-effort (as an optional injection dep) - TypeName.create("io.helidon.inject.configdriven.tests.config.FakeTracer"), - // ZImpl is intercepted - TypeName.create("io.helidon.inject.configdriven.interceptor.test.ZImpl") - )); - assertThat("lookup log: " + criteriaSearchLog, - metrics.lookupCount().orElseThrow(), - is(3)); - } - - @Test - public void startupAndShutdownRunLevelServices() { - resetWith(io.helidon.config.Config.builder(createBasicTestingConfigSource(), createRootDefault8080TestingConfigSource()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build()); - - Metrics metrics = injectionServices.metrics().orElseThrow(); - int startingLookupCount = metrics.lookupCount().orElseThrow(); - - MatcherAssert.assertThat(ASimpleRunLevelService.getPostConstructCount(), - is(0)); - assertThat(ASimpleRunLevelService.getPreDestroyCount(), - is(0)); - - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .runLevel(RunLevel.STARTUP) - .build(); - List> startups = services.lookupAll(criteria); - List desc = startups.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat(desc, - contains(ASimpleRunLevelService.class.getSimpleName() + ":INIT")); - startups.forEach(ServiceProvider::get); - - metrics = injectionServices.metrics().orElseThrow(); - int endingLookupCount = metrics.lookupCount().orElseThrow(); - assertThat(endingLookupCount - startingLookupCount, - is(1)); - - assertThat(ASimpleRunLevelService.getPostConstructCount(), - is(1)); - assertThat(ASimpleRunLevelService.getPreDestroyCount(), - is(0)); - - injectionServices.shutdown(); - assertThat(ASimpleRunLevelService.getPostConstructCount(), - is(1)); - assertThat(ASimpleRunLevelService.getPreDestroyCount(), - is(1)); - } - -} diff --git a/inject/configdriven/tests/configuredby/README.md b/inject/configdriven/tests/configuredby/README.md deleted file mode 100644 index 7b31e3abba0..00000000000 --- a/inject/configdriven/tests/configuredby/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# inject-configdriven-test-configuredby - -Tests for full ConfiguredBy-generated service types. diff --git a/inject/configdriven/tests/configuredby/pom.xml b/inject/configdriven/tests/configuredby/pom.xml deleted file mode 100644 index b5efeba23e2..00000000000 --- a/inject/configdriven/tests/configuredby/pom.xml +++ /dev/null @@ -1,159 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject.configdriven.tests - helidon-inject-configdriven-tests-project - 4.2.0-SNAPSHOT - - helidon-inject-configdriven-tests-configuredby - Helidon Injection ConfigDriven Tests CfgedBy Svc - - Tests the fuller config-driven services (i.e., full config not just common and with config-driven services) - - - - - io.helidon.inject.configdriven.tests - helidon-inject-configdriven-tests-config - ${helidon.version} - - - io.helidon.builder - helidon-builder-api - - - io.helidon.inject.configdriven - helidon-inject-configdriven-api - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-yaml - - - io.helidon.config - helidon-config-metadata - true - - - io.helidon.inject.configdriven - helidon-inject-configdriven-runtime - - - jakarta.inject - jakarta.inject-api - provided - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - provided - true - - - io.helidon.common.testing - helidon-common-testing-junit5 - compile - - - io.helidon.inject - helidon-inject-testing - compile - - - org.hamcrest - hamcrest-all - compile - - - org.junit.jupiter - junit-jupiter-api - compile - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - alphabetical - - - - org.apache.maven.plugins - maven-compiler-plugin - - - -Ainject.autoAddNonContractInterfaces=true - - true - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - ${helidon.version} - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.inject.configdriven - helidon-inject-configdriven-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - - diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonConfigBeanBlueprint.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonConfigBeanBlueprint.java deleted file mode 100644 index 6931feb3f9e..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonConfigBeanBlueprint.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.inject.configdriven.api.ConfigBean; - -@ConfigBean(wantDefault = true, atLeastOne = true) -@Configured(root = true) -@Prototype.Blueprint -interface ASingletonConfigBeanBlueprint { - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonService.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonService.java deleted file mode 100644 index f1aa6c6aa15..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonService.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import io.helidon.inject.configdriven.api.ConfigDriven; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Named; - -@ConfigDriven(value = ASingletonConfigBeanBlueprint.class, activateByDefault = true) -@Named("jane") -class ASingletonService implements ASingletonServiceContract { - private boolean running; - - // note: initially left w/o a ctor here! - - /** - * For Testing. - */ - @PostConstruct - public void initialize() { - assert (!running); - running = true; - } - - /** - * For Testing. - */ - @PreDestroy - public void shutdown() { - running = false; - } - - /** - * For Testing. - */ - @Override - public boolean isRunning() { - return running; - } - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonServiceContract.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonServiceContract.java deleted file mode 100644 index b0289c2398c..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/ASingletonServiceContract.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -/** - * For Testing. - */ -public interface ASingletonServiceContract { - - /** - * For Testing. - */ - boolean isRunning(); - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractConfigBeanTest.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractConfigBeanTest.java deleted file mode 100644 index fca73b62447..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractConfigBeanTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import java.util.List; -import java.util.Map; - -import io.helidon.common.Errors; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.configdriven.tests.config.TestClientConfig; -import io.helidon.inject.configdriven.tests.config.TestServerConfig; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasEntry; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * See {@code BasicConfigBeanTest}, this repeats some of that with a fuller classpath with config-driven-services and full config - * enabled. This means that extra validation (e.g., required config attributes, etc.) will be tested here. - */ -public class AbstractConfigBeanTest { - - @Test - void emptyConfig() { - Config cfg = Config.create(); - Errors.ErrorMessagesException e = assertThrows(Errors.ErrorMessagesException.class, () -> TestServerConfig.builder().config(cfg).build()); - assertThat(e.getMessage(), - containsString("\"port\" is required, but not set")); - } - - @Test - void minimalConfig() { - Config cfg = Config.builder( - ConfigSources.create( - Map.of("port", "8080", - "cipher-suites", "a,b,c", - "headers.0", "header1", - "headers.1", "header2"), - "my-simple-config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - TestServerConfig serverConfig = TestServerConfig.builder().config(cfg).build(); - assertThat(serverConfig.description(), - optionalEmpty()); - assertThat(serverConfig.name(), - equalTo("default")); - assertThat(serverConfig.port(), - equalTo(8080)); - assertThat(serverConfig.cipherSuites(), - contains("a", "b", "c")); - - TestClientConfig clientConfig = TestClientConfig.builder().config(cfg).build(); - assertThat(clientConfig.pswd(), - is(new char[0])); - assertThat(clientConfig.name(), - equalTo("default")); - assertThat(clientConfig.port(), - equalTo(8080)); - assertThat(clientConfig.cipherSuites(), - contains("a", "b", "c")); - assertThat(clientConfig.headers(), - hasEntry("0", "header1")); - assertThat(clientConfig.headers(), - hasEntry("1", "header2")); - } - - /** - * Callers can conceptually use config beans as just plain old vanilla builders, void of any config usage. - */ - @Test - void noConfig() { - TestServerConfig serverConfig = TestServerConfig.builder() - .port(0) - .build(); - assertThat(serverConfig.description(), - optionalEmpty()); - assertThat(serverConfig.name(), - equalTo("default")); - assertThat(serverConfig.port(), - equalTo(0)); - assertThat(serverConfig.cipherSuites(), - equalTo(List.of())); - - serverConfig = TestServerConfig.builder(serverConfig).port(123).build(); - assertThat(serverConfig.description(), - optionalEmpty()); - assertThat(serverConfig.name(), - equalTo("default")); - assertThat(serverConfig.port(), - equalTo(123)); - assertThat(serverConfig.cipherSuites(), - equalTo(List.of())); - - TestClientConfig clientConfig = TestClientConfig.builder() - .port(0) - .build(); - assertThat(clientConfig.name(), - equalTo("default")); - assertThat(clientConfig.port(), - equalTo(0)); - assertThat(clientConfig.headers(), - equalTo(Map.of())); - assertThat(clientConfig.cipherSuites(), - equalTo(List.of())); - - clientConfig = TestClientConfig.builder(clientConfig).port(123).build(); - assertThat(clientConfig.name(), - equalTo("default")); - assertThat(clientConfig.port(), - equalTo(123)); - assertThat(clientConfig.headers(), - equalTo(Map.of())); - assertThat(clientConfig.cipherSuites(), - equalTo(List.of())); - } - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractConfiguredByTest.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractConfiguredByTest.java deleted file mode 100644 index dee7141e480..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractConfiguredByTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.MapConfigSource; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.configdriven.api.ConfigDriven; -import io.helidon.inject.configdriven.api.NamedInstance; -import io.helidon.inject.configdriven.runtime.ConfigBeanRegistry; -import io.helidon.inject.configdriven.tests.config.FakeServerConfig; -import io.helidon.inject.configdriven.tests.config.FakeTlsWSNotDrivenByCB; -import io.helidon.inject.configdriven.tests.config.FakeWebServer; -import io.helidon.inject.configdriven.tests.config.FakeWebServerContract; -import io.helidon.inject.testing.InjectionTestingSupport; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * Tests for {@link ConfigDriven}. - */ -public abstract class AbstractConfiguredByTest { - protected static final String FAKE_SOCKET_CONFIG = "sockets"; - protected static final String FAKE_SERVER_CONFIG = "fake-server"; - - protected InjectionServices injectionServices; - protected Services services; - - @BeforeAll - static void initialStateChecks() { - ConfigBeanRegistry cbr = ConfigBeanRegistry.instance(); - assertThat(cbr.ready(), is(false)); - } - - @AfterAll - static void tearDown() { - InjectionTestingSupport.resetAll(); - } - - protected void resetWith(Config config) { - InjectionTestingSupport.resetAll(); - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); - } - - public MapConfigSource.Builder createBasicTestingConfigSource() { - return ConfigSources.create( - Map.of( - "inject.permits-dynamic", "true", - "inject.activation-logs", "true", - "inject.service-lookup-caching", "true" - ), "config-basic"); - } - - public MapConfigSource.Builder createRootDefault8080TestingConfigSource() { - return ConfigSources.create( - Map.of( - "server.name", "fake-server", - "server.port", "8080", - "server.worker-count", "1" - ), "config-root-default-8080"); - } - - @Test - void testItAll() { - resetWith(io.helidon.config.Config.builder(createBasicTestingConfigSource(), createRootDefault8080TestingConfigSource()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build()); - - // verify the services registry - testRegistry(); - - ServiceProvider fakeWebServer = services.lookup(FakeWebServer.class); - assertThat(fakeWebServer.currentActivationPhase(), is(Phase.ACTIVE)); - assertThat(fakeWebServer.get().isRunning(), is(true)); - - ServiceProvider singletonService = services.lookup(ASingletonService.class); - assertThat(singletonService.currentActivationPhase(), is(Phase.ACTIVE)); - assertThat(singletonService.get().isRunning(), is(true)); - - // verify the bean registry - testBeanRegistry(); - - // shutdown has to come next - testShutdown(fakeWebServer.get()); - } - - // @Test - void testRegistry() { - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addQualifier(Qualifier.create(ConfigDriven.class)) - .build(); - List> list = services.lookupAll(criteria); - List desc = list.stream() - .filter(it -> !it.serviceInfo().serviceTypeName().resolvedName().contains(".yaml.")) - .map(ServiceProvider::description) - .collect(Collectors.toList()); - // order matters here since it should be based upon weight - assertThat("root providers are config-driven, auto-started services unless overridden to not be driven", desc, - containsInAnyOrder("ASingletonService{root}:ACTIVE", - "FakeTlsWSNotDrivenByCB{root}:PENDING", - "FakeWebServer{root}:ACTIVE", - "FakeWebServerNotDrivenAndHavingConfiguredByOverrides{root}:PENDING", - "SomeConfiguredServiceWithAnAbstractBase{root}:PENDING" - )); - - criteria = ServiceInfoCriteria.builder() - .addContractImplemented(FakeWebServerContract.class) - .build(); - list = services.lookupAll(criteria); - desc = list.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat("no root providers expected in result, but all are auto-started unless overridden", desc, - contains("FakeWebServer{@default}:ACTIVE", - "FakeWebServerNotDrivenAndHavingConfiguredByOverrides{@default}:PENDING")); - - criteria = ServiceInfoCriteria.builder() - .serviceTypeName(TypeName.create(FakeTlsWSNotDrivenByCB.class)) - .build(); - list = services.lookupAll(criteria); - desc = list.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat("root providers expected here since we looked up by service type name", desc, - contains("FakeTlsWSNotDrivenByCB{root}:PENDING")); - - criteria = ServiceInfoCriteria.builder() - .addContractImplemented(FakeTlsWSNotDrivenByCB.class) - .addQualifier(Qualifier.createNamed("*")) - .build(); - list = services.lookupAll(criteria); - desc = list.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat("root providers expected here since no configuration for this service", desc, - contains("FakeTlsWSNotDrivenByCB{root}:PENDING")); - - ServiceProvider fakeTlsProvider = list.get(0); - InjectionServiceProviderException e = assertThrows(InjectionServiceProviderException.class, fakeTlsProvider::get); - assertThat("There is no configuration, so cannot activate this service", e.getMessage(), - equalTo("Expected to find a match: service provider: FakeTlsWSNotDrivenByCB{root}:PENDING")); - - criteria = ServiceInfoCriteria.builder() - .addContractImplemented(ASingletonService.class) - .addQualifier(Qualifier.createNamed("jane")) - .build(); - list = services.lookupAll(criteria); - desc = list.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat("Slave providers expected here since we have default configuration for this service", desc, - contains("ASingletonService{@default}:ACTIVE")); - } - - // @Test - void testShutdown(FakeWebServer fakeWebServer) { - assertThat(fakeWebServer.isRunning(), is(true)); - - injectionServices.shutdown(); - - assertThat(fakeWebServer.isRunning(), is(false)); - } - - // @Test - void testBeanRegistry() { - ConfigBeanRegistry cbr = ConfigBeanRegistry.instance(); - assertThat(cbr.ready(), is(true)); - - Map, List>> beansByType = cbr.allConfigBeans(); - List> namedInstances = beansByType.get(FakeServerConfig.class); - - assertThat("We should have instances created for FakeServerConfig", namedInstances, notNullValue()); - - List names = namedInstances.stream() - .map(NamedInstance::name) - .toList(); - - // only default is created - assertThat(names, hasItems("@default")); - } - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractServiceBase.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractServiceBase.java deleted file mode 100644 index 35cafb4cb70..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/AbstractServiceBase.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import java.util.concurrent.atomic.AtomicInteger; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; - -public abstract class AbstractServiceBase implements SomeServiceInterface { - private final AtomicInteger postConstructCallCount = new AtomicInteger(); - private final AtomicInteger preDestroyCallCount = new AtomicInteger(); - - @PostConstruct - void postConstruct() { - postConstructCallCount.incrementAndGet(); - } - - int postConstructCallCount() { - return postConstructCallCount.get(); - } - - @PreDestroy - void preDestroy() { - preDestroyCallCount.incrementAndGet(); - } - - int preDestroyCallCount() { - return preDestroyCallCount.get(); - } - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeConfiguredServiceWithAnAbstractBase.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeConfiguredServiceWithAnAbstractBase.java deleted file mode 100644 index da07a4876a1..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeConfiguredServiceWithAnAbstractBase.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import io.helidon.inject.configdriven.api.ConfigDriven; - -import jakarta.inject.Inject; - -@ConfigDriven(SomeServiceConfigBlueprint.class) -public class SomeConfiguredServiceWithAnAbstractBase extends AbstractServiceBase { - final SomeServiceConfig cfg; - - @Inject - SomeConfiguredServiceWithAnAbstractBase(SomeServiceConfig cfg) { - assert (cfg != null); - assert (!cfg.name().isBlank()); - this.cfg = cfg; - } - - @Override - public String name() { - return cfg.name(); - } - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeServiceConfigBlueprint.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeServiceConfigBlueprint.java deleted file mode 100644 index f8b8ec936d3..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeServiceConfigBlueprint.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -@Configured(root = true) -@Prototype.Blueprint -interface SomeServiceConfigBlueprint { - @ConfiguredOption("") - String name(); -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeServiceInterface.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeServiceInterface.java deleted file mode 100644 index 8a7732ff514..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/SomeServiceInterface.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -public interface SomeServiceInterface { - - String name(); - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/package-info.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/package-info.java deleted file mode 100644 index ce8c48009fb..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/test/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * For testing. - */ -package io.helidon.inject.configdriven.configuredby.test; diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/Async.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/Async.java deleted file mode 100644 index aa5f1a164cf..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/Async.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.yaml.test; - -import io.helidon.inject.configdriven.api.ConfigDriven; - -import jakarta.inject.Inject; - -@ConfigDriven(AsyncConfigBlueprint.class) -public class Async { - - final AsyncConfig cfg; - - @Inject - Async(AsyncConfig cfg) { - this.cfg = cfg; - } - - public AsyncConfig config() { - return cfg; - } -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/AsyncConfigBlueprint.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/AsyncConfigBlueprint.java deleted file mode 100644 index 57926e96760..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/AsyncConfigBlueprint.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.yaml.test; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.inject.configdriven.api.ConfigBean; - -@ConfigBean(repeatable = true) -@Configured(root = true, prefix = "ft.asyncs") -@Prototype.Blueprint -interface AsyncConfigBlueprint { - @ConfiguredOption - String executor(); - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/BulkheadConfigBlueprint.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/BulkheadConfigBlueprint.java deleted file mode 100644 index 83f2225b777..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/BulkheadConfigBlueprint.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.yaml.test; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -@Configured(root = true, prefix = "ft.bulkheads") -@Prototype.Blueprint -interface BulkheadConfigBlueprint { - - @ConfiguredOption("0") - int queue(); - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/ServerConfigBlueprint.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/ServerConfigBlueprint.java deleted file mode 100644 index 267ddc669a0..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/ServerConfigBlueprint.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.yaml.test; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; - -@Configured -@Prototype.Blueprint -interface ServerConfigBlueprint { - - @ConfiguredOption("0") - int port(); - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/package-info.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/package-info.java deleted file mode 100644 index b287b5e4e95..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/configuredby/yaml/test/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection ConfiguredBy tests driven testing from the {@code application.yaml} config under test/resources. - */ -package io.helidon.inject.configdriven.configuredby.yaml.test; diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/IZ.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/IZ.java deleted file mode 100644 index 97b6cf6ffa5..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/IZ.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.interceptor.test; - -import io.helidon.inject.api.Contract; - -@Contract -public interface IZ { - - String methodIZ1(String arg1); - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/TestInterceptorTrigger.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/TestInterceptorTrigger.java deleted file mode 100644 index dcb6510a2de..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/TestInterceptorTrigger.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.interceptor.test; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import io.helidon.inject.api.InterceptedTrigger; - -@InterceptedTrigger -@Retention(RetentionPolicy.CLASS) -public @interface TestInterceptorTrigger { -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/ZImpl.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/ZImpl.java deleted file mode 100644 index d413cf5b099..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/ZImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.interceptor.test; - -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.inject.api.InterceptedTrigger; -import io.helidon.inject.configdriven.tests.config.FakeWebServer; - -import jakarta.annotation.PostConstruct; -import jakarta.inject.Inject; - -/** - * This test case is applying {@link io.helidon.inject.api.InterceptorBasedAnno} (an {@link InterceptedTrigger}) - * on this class directly. Since it is a config-driven service it is forced to used the interface based approach to interceptors. - */ -// TODO: https://github.com/helidon-io/helidon/issues/6542 -@TestInterceptorTrigger -//@ConfiguredBy(ZImplConfig.class) -@SuppressWarnings("ALL") -public class ZImpl implements IZ { - private final AtomicInteger postConstructCallCount = new AtomicInteger(); - -// @Inject -// ZImpl(ZImplConfig config/*, -// List> singletons*/) { -// assert (config != null && !config.name().isEmpty()) : Objects.toString(config); -//// assert (singletons.size() == 1) : singletons.toString(); -// } - - @Inject - ZImpl(Optional fakeWebServer) { - assert (fakeWebServer.isPresent()); - } - - @Override - public String methodIZ1(String val) { - return "methodIZ1:" + val; - } - - @PostConstruct - void postConstruct() { - postConstructCallCount.incrementAndGet(); - } - - int postConstructCallCount() { - return postConstructCallCount.get(); - } - -} diff --git a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/ZImplConfigBlueprint.java b/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/ZImplConfigBlueprint.java deleted file mode 100644 index a3fccfa4095..00000000000 --- a/inject/configdriven/tests/configuredby/src/main/java/io/helidon/inject/configdriven/interceptor/test/ZImplConfigBlueprint.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.interceptor.test; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; - -/** - * Drives {@link ZImpl} activation. - */ -@Prototype.Blueprint -@Configured -interface ZImplConfigBlueprint { - - /** - * For testing purposes. - * - * @return for testing purposes - */ - String name(); - -} diff --git a/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/test/ConfiguredByTest.java b/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/test/ConfiguredByTest.java deleted file mode 100644 index a62691b4291..00000000000 --- a/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/test/ConfiguredByTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.MapConfigSource; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.configdriven.api.NamedInstance; -import io.helidon.inject.configdriven.configuredby.yaml.test.Async; -import io.helidon.inject.configdriven.runtime.ConfigBeanRegistry; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasKey; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.collection.IsCollectionWithSize.hasSize; - -/** - * Executes the tests from the base. - */ -class ConfiguredByTest extends AbstractConfiguredByTest { - @Test - void testRepeatableConfigBean() { - resetWith(Config.create()); - - List serviceProviders = services.lookupAll(Async.class) - .stream() - .map(ServiceProvider::get) - .toList(); - - assertThat(serviceProviders, hasSize(2)); - - Async async = services.lookup(Async.class, "first").get(); - assertThat(async.config(), notNullValue()); - assertThat(async.config().executor(), is("exec")); - - async = services.lookup(Async.class, "second").get(); - assertThat(async.config(), notNullValue()); - assertThat(async.config().executor(), is("service")); - } - - @Test - void onlyRootConfigBeansAreCreated() { - resetWith(io.helidon.config.Config.builder(createBasicTestingConfigSource(), - createRootDefault8080TestingConfigSource(), - createNested8080TestingConfigSource()) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build()); - - ConfigBeanRegistry cbr = ConfigBeanRegistry.instance(); - assertThat(cbr.ready(), - is(true)); - - Map, List>> beans = cbr.allConfigBeans(); - assertThat(beans, hasKey(SomeServiceConfig.class)); - assertThat(beans, hasKey(ASingletonConfigBean.class)); - - assertHasNamed(beans.get(SomeServiceConfig.class), "@default"); - assertHasNamed(beans.get(ASingletonConfigBean.class), "@default"); - } - - private void assertHasNamed(List> namedInstances, String... expectedNames) { - List nameList = namedInstances.stream() - .map(NamedInstance::name) - .toList(); - Set nameSet = Set.copyOf(nameList); - - assertThat("Names should be unique.", nameList, is(List.copyOf(nameSet))); - assertThat(nameSet, contains(expectedNames)); - } - - protected MapConfigSource.Builder createNested8080TestingConfigSource() { - return ConfigSources.create( - Map.of( - "nested." + FAKE_SERVER_CONFIG + ".0.name", "nested", - "nested." + FAKE_SERVER_CONFIG + ".0.port", "8080", - "nested." + FAKE_SERVER_CONFIG + ".0.worker-count", "1" - ), "config-nested-default-8080"); - } - -} diff --git a/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/test/DefaultConfigBeanTest.java b/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/test/DefaultConfigBeanTest.java deleted file mode 100644 index 8c3045d843a..00000000000 --- a/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/test/DefaultConfigBeanTest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.test; - -/** - * Executes the tests from the base. - */ -class DefaultConfigBeanTest extends AbstractConfigBeanTest { - -} diff --git a/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/yaml/test/NamedConfiguredByTest.java b/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/yaml/test/NamedConfiguredByTest.java deleted file mode 100644 index 99c2bf98058..00000000000 --- a/inject/configdriven/tests/configuredby/src/test/java/io/helidon/inject/configdriven/configuredby/yaml/test/NamedConfiguredByTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.configdriven.configuredby.yaml.test; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.common.testing.junit5.OptionalMatcher; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.config.yaml.YamlConfigParser; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Services; -import io.helidon.inject.configdriven.api.NamedInstance; -import io.helidon.inject.configdriven.runtime.ConfigBeanRegistry; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; - -class NamedConfiguredByTest { - InjectionServices injectionServices; - Services services; - - @BeforeAll - static void initialStateChecks() { - ConfigBeanRegistry cbr = ConfigBeanRegistry.instance(); - assertThat(cbr.ready(), is(false)); - } - - @AfterAll - static void tearDown() { - resetAll(); - } - - void resetWith(Config config) { - resetAll(); - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); - } - - @BeforeEach - void setup() { - Optional existingBootstrap = InjectionServices.globalBootstrap(); - assertThat(existingBootstrap, OptionalMatcher.optionalEmpty()); - - Config config = Config.builder() - .addSource(ConfigSources.classpath("application.yaml")) - .addParser(YamlConfigParser.create()) - .disableSystemPropertiesSource() - .disableEnvironmentVariablesSource() - .build(); - resetWith(config); - } - - @Test - void namedConfiguredServices() { - ConfigBeanRegistry cbr = ConfigBeanRegistry.instance(); - Map, List>> allConfigBeans = cbr.allConfigBeans(); - - List> namedInstances = allConfigBeans.get(AsyncConfig.class); - - assertThat(namedInstances.stream().map(NamedInstance::name).toList(), - containsInAnyOrder("first", "second")); - } - -} diff --git a/inject/configdriven/tests/configuredby/src/test/resources/application.yaml b/inject/configdriven/tests/configuredby/src/test/resources/application.yaml deleted file mode 100644 index dcea557cf3a..00000000000 --- a/inject/configdriven/tests/configuredby/src/test/resources/application.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -inject: - permits-dynamic: true - -server: - port: 8080 -ft: - asyncs: - first: - executor: "exec" - second: - executor: "service" - bulkheads: - - queue: 10 diff --git a/inject/configdriven/tests/pom.xml b/inject/configdriven/tests/pom.xml deleted file mode 100644 index 7e92ef1d5e1..00000000000 --- a/inject/configdriven/tests/pom.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - 4.0.0 - - io.helidon.inject.configdriven - helidon-inject-configdriven-project - 4.2.0-SNAPSHOT - - io.helidon.inject.configdriven.tests - helidon-inject-configdriven-tests-project - Helidon Injection ConfigDriven Tests Project - pom - - - true - true - true - true - true - true - - - - config - configuredby - configuredby-application - - - diff --git a/inject/maven-plugin/README.md b/inject/maven-plugin/README.md deleted file mode 100644 index 9df010f2199..00000000000 --- a/inject/maven-plugin/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# inject-maven-plugin -A collection of maven plugins for Injection-based applications that provides several features including options to: - -1. Validate the entirety of dependency graph across all modules. The application-create plugin would be applied in the same pom.xml - that would otherwise assemble your application for deployment. This module would be expected to have compile-time references to - each module that contributes to your application holistically - -2. After the model has been validated, the application-create plugin will code-generate the service provider "Activators", "Modules", and "Application" into the - final assembly that will be used at runtime to satisfy every injection point for the entire application without the need for reflection at runtime. This can be thought conceptually as a "linking phase" for your native application/image. - -3. Creating Injection modules from external jars and packages using the . - ---- - -Q: Is this maven plugin required for your Injection-based application to work? - -Answer 1: No, but it is recommended. Strictly speaking the main code generation occurs using the annotation processor, and the output from that processor is fully functional at runtime. However, without the use of this plugin your application's dependency model will not be validation nor will it be linked/bound/burned into your final application image. It will still work fine and Injection will handle this case, but your application is not as optimal from a runtime performance perspective. - -Answer 2: Yes, but only if you do not have access to the service implementation types, and are unable to apply the annotation processor on those types at compile time. Note, however, that Injection can still work without the maven processor in cases where you have possession to rebuild the service classes, but get the interfaces from an external module. In this later case, the ExternalContracts interfaces can be used on the service implementation classes. - ---- - -## Usage - -The following are the maven Mojo's that are available to use. Each can be used for either the src/main or src/test. - -example usage: -```pom.xml - - io.helidon.inject - helidon-inject-maven-plugin - ${helidon.version} - - - - external-module-create - - - - compile - compile - - application-create - - - - - - io.helidon.inject.examples.logger.common - - ALL - - -``` - -### application-create -This goal is used to trigger the creation of the Injection$$Application for your module (which typically is found in the final assembly jar module for your application). The usage of this also triggers the validation and integrity checks for your entire application's DI model, and will fail-fast at compilation time if any issue is detected (e.g., a non-Optional @Inject is found on a contract type having no concrete service implementations, etc.). Assuming there are no issues found during application creation - each of your service implementations will be listed inside the injectionApplication, and it will include the literal DI resolution plan for each of your services. This can also be very useful for visualization and debugging purposes besides being optimal from a runtime performance perspective. - -Also note that Helidon Injection strives to ensure your application stays as deterministic as possible (as shown by the Injection$$Application/i> generated class). But when the jakarta.inject.Provider type is used within your application then some of that deterministic behavior goes away. This is due to how Provider<>'s work since the implementation for the Provider (i.e., your application logic) "owns" the behavior for what actual concrete type that are created by it, along with the scope/cardinality for those instances. These instances are then delivered (as potentially injectable services) into other dependent services. In this way Helidon Injection is simply acting as a broker and delivery mechanism between your Provider<> implementation(s) and the consumer that are using those service instances as injection points, etc. This is not meant to scare ore even dissuade you from using Provider<>, but merely to inform you that some of the deterministic behavior goes away under these circumstances using Provider instead of another Scope type like @Singleton. In many/most cases this is completely normal and acceptable. As a precaution, however, Helidon Injection chose to fail-fast at application creation time if your application is found to use jakarta.inject.Provider. You will then need to provide a strategy/configuration in your pom.xml file to permit these types of usages. There are options to allow ALL providers (as shown in the above example), or the strategy can be dictated on a case-by-case basis. See the javadoc for [AbstractApplicationCreatorMojo](src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java) for details. - -### external-module-create -This goal is used to trigger the creation of the supporting set of DI classes for an external jar/module - typically created without since it lacked having the Injection annotation processor during compilation. In this scenario, and to use this option then first be sure that the dependent module is a maven compile-time dependency in your module. After that then simply state the name of the package(s) to scan and produce the supporting DI classes (e.g., "io.helidon.inject.examples.logger.common" in the above example) in the pom.xml and then target/generated-sources/inject should be generated accordingly. - -The example from above cover the basics for generation. There are one more advanced option that is available here that we'd like to cover. The below was taken from the [test-tck-jsr330 pom.xml](../tests/tck-jsr330/pom.xml): - -```pom.xml - - - -Ainject.debug=true - -Ainject.autoAddNonContractInterfaces=true - - - org.atinject.tck.auto - org.atinject.tck.auto.accessories - - true - - - org.atinject.tck.auto.accessories.SpareTire - - - jakarta.inject.Named - spare - - - - - org.atinject.tck.auto.DriversSeat - - - org.atinject.tck.auto.Drivers - - - - - -``` - -Here we can see additional DI constructs, specifically two Qualifiers, are being augmented into the DI declaration model for the 3rd party jar. We can also see the option used to treat all service type interfaces as Contracts. - -## TestApplication -When the maven plugin creates an application for src/main/java sources, a Injection$$Application will be created for compile-time dependencies involved in the DI set of services. But when src/test/java sources are compiled, a Injection$$TestApplication will be created for test-type dependencies involved in the test-side DI set of services of your application. - -## Best Practices -Only one Injection$$Application should typically be in your module classpath. And in production applications there should never be any test service types or a Injection$$TestApplication, etc. diff --git a/inject/maven-plugin/etc/spotbugs/exclude.xml b/inject/maven-plugin/etc/spotbugs/exclude.xml deleted file mode 100644 index aff67c8c0d4..00000000000 --- a/inject/maven-plugin/etc/spotbugs/exclude.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inject/maven-plugin/pom.xml b/inject/maven-plugin/pom.xml deleted file mode 100644 index bb0add44ab9..00000000000 --- a/inject/maven-plugin/pom.xml +++ /dev/null @@ -1,189 +0,0 @@ - - - - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-maven-plugin - Helidon Injection Maven Plugin - maven-plugin - - - true - 2.7.0 - 3.3.0 - 3.9.3 - 3.9.0 - 3.9.0 - 2.2.1 - - etc/spotbugs/exclude.xml - - - - - - org.apache.maven.plugins - maven-plugin-plugin - - - - report - - - - - - - - - - - org.codehaus.plexus - plexus-classworlds - ${version.plexus.classworlds} - - - org.codehaus.plexus - plexus-utils - ${version.plexus.utils} - - - org.apache.maven - maven-artifact - ${version.plugin.api} - provided - - - - - io.helidon.inject - helidon-inject-tools - - - - io.helidon.inject.configdriven - helidon-inject-configdriven-runtime - - - io.helidon.builder - helidon-builder-api - - - io.helidon.config - helidon-config - - - jakarta.inject - jakarta.inject-api - compile - - - jakarta.annotation - jakarta.annotation-api - - - com.github.jknack - handlebars - - - io.github.classgraph - classgraph - - - org.apache.maven - maven-plugin-api - ${version.plugin.api} - provided - - - org.codehaus.plexus - plexus-classworlds - - - org.codehaus.plexus - plexus-utils - - - - - org.apache.maven.plugin-tools - maven-plugin-annotations - ${version.plugin.annotations} - provided - - - org.apache.maven - maven-project - ${version.plugin.project} - provided - - - org.apache.maven - maven-model - - - org.codehaus.plexus - plexus-utils - - - org.apache.maven - maven-artifact - - - - - - - - - - org.apache.maven.plugins - maven-plugin-plugin - ${version.plugin.plugin} - - - - - - [3.6.1,) - [${version.java}.0,) - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - -proc:none - - - - - - diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java deleted file mode 100644 index 9eea0bfb84a..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.io.File; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.CallingContext; -import io.helidon.inject.api.CallingContextFactory; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.runtime.ServiceBinderDefault; -import io.helidon.inject.tools.AbstractFilerMessager; -import io.helidon.inject.tools.ActivatorCreatorCodeGen; -import io.helidon.inject.tools.ApplicationCreatorCodeGen; -import io.helidon.inject.tools.ApplicationCreatorConfigOptions; -import io.helidon.inject.tools.ApplicationCreatorRequest; -import io.helidon.inject.tools.ApplicationCreatorResponse; -import io.helidon.inject.tools.CodeGenFiler; -import io.helidon.inject.tools.CodeGenPaths; -import io.helidon.inject.tools.CompilerOptions; -import io.helidon.inject.tools.ModuleInfoDescriptor; -import io.helidon.inject.tools.PermittedProviderType; -import io.helidon.inject.tools.ToolsException; -import io.helidon.inject.tools.spi.ApplicationCreator; - -import org.apache.maven.model.Build; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; - -import static io.helidon.inject.api.CallingContextFactory.globalCallingContext; -import static io.helidon.inject.runtime.InjectionExceptions.toErrorMessage; -import static io.helidon.inject.tools.ModuleUtils.REAL_MODULE_INFO_JAVA_NAME; -import static io.helidon.inject.tools.ModuleUtils.isUnnamedModuleName; -import static io.helidon.inject.tools.ModuleUtils.toBasePath; -import static io.helidon.inject.tools.ModuleUtils.toSuggestedModuleName; -import static java.util.Optional.ofNullable; - -/** - * Abstract base for the Injection {@code maven-plugin} responsible for creating {@code Application} and Test {@code Application}'s. - * - * @see Application - * @see ApplicationCreatorConfigOptions - */ -@SuppressWarnings({"unused", "FieldCanBeLocal"}) -public abstract class AbstractApplicationCreatorMojo extends AbstractCreatorMojo { - - /** - * The approach for handling providers. - * See {@code ApplicationCreatorConfigOptions#permittedProviderTypes()}. - */ - @Parameter(property = "inject.permitted.provider.types", readonly = true) - private String permittedProviderTypes; - private PermittedProviderType permittedProviderType; - - /** - * Sets the named types permitted for providers, assuming use of - * {@link PermittedProviderType#NAMED}. - */ - @Parameter(property = "inject.permitted.provider.type.names", readonly = true) - private List permittedProviderTypeNames; - - /** - * Sets the named qualifier types permitted for providers, assuming use of - * {@link PermittedProviderType#NAMED}. - */ - @Parameter(property = "inject.permitted.provider.qualifier.type.names", readonly = true) - private List permittedProviderQualifierTypeNames; - - /** - * Default constructor. - */ - protected AbstractApplicationCreatorMojo() { - } - - static ToolsException noModuleFoundError() { - return new ToolsException("Unable to determine the name of the current module - " - + "was APT run and do you have a module-info?"); - } - - static ToolsException noModuleFoundError(String moduleName) { - return new ToolsException("No Injection module named '" + moduleName - + "' was found in the current module - was APT run?"); - } - - String getThisModuleName() { - Build build = getProject().getBuild(); - Path basePath = toBasePath(build.getSourceDirectory()); - String moduleName = toSuggestedModuleName(basePath, Path.of(build.getSourceDirectory()), true).orElseThrow(); - if (isUnnamedModuleName(moduleName)) { - // try to recover it from a previous tooling step - String appPackageName = loadAppPackageName().orElse(null); - if (appPackageName == null) { - getLog().info(noModuleFoundError().getMessage()); - } else { - moduleName = appPackageName; - } - } - return moduleName; - } - - Optional> lookupThisModule(String name, - Services services, - boolean expected) { - Optional> result = services.lookupFirst(ModuleComponent.class, name, false); - if (result.isEmpty() && expected) { - throw noModuleFoundError(name); - } - return result; - } - - String getClassPrefixName() { - return ActivatorCreatorCodeGen.DEFAULT_CLASS_PREFIX_NAME; - } - - abstract String getGeneratedClassName(); - - abstract File getOutputDirectory(); - - List getSourceRootPaths() { - return getNonTestSourceRootPaths(); - } - - List getNonTestSourceRootPaths() { - MavenProject project = getProject(); - List result = new ArrayList<>(project.getCompileSourceRoots().size()); - for (Object a : project.getCompileSourceRoots()) { - result.add(Path.of(a.toString())); - } - return result; - } - - List getTestSourceRootPaths() { - MavenProject project = getProject(); - List result = new ArrayList<>(project.getTestCompileSourceRoots().size()); - for (Object a : project.getTestCompileSourceRoots()) { - result.add(Path.of(a.toString())); - } - return result; - } - - LinkedHashSet getModulepathElements() { - return getSourceClasspathElements(); - } - - boolean hasModuleInfo() { - return getSourceRootPaths().stream() - .anyMatch(p -> new File(p.toFile(), REAL_MODULE_INFO_JAVA_NAME).exists()); - } - - /** - * Favors the 'test' module-info if available, and falls back to 'main' module-info. - * - * @param location the location for the located module-info - * @return the module-info descriptor to return or null if none is available - */ - ModuleInfoDescriptor getAnyModuleInfo(AtomicReference location) { - File file = getNonTestSourceRootPaths().stream() - .map(p -> new File(p.toFile(), REAL_MODULE_INFO_JAVA_NAME)) - .filter(File::exists) - .findFirst() - .orElse(null); - - if (file == null) { - file = getTestSourceRootPaths().stream() - .map(p -> new File(p.toFile(), REAL_MODULE_INFO_JAVA_NAME)) - .filter(File::exists) - .findFirst() - .orElse(null); - } - - if (file != null && location != null) { - location.set(file); - return ModuleInfoDescriptor.create(file.toPath()); - } - - return null; - } - - /** - * @return This represents the set of services that we already code-gen'ed - */ - Set getServiceTypeNamesForExclusion() { - getLog().info("excluding service type names: []"); - return Set.of(); - } - - @Override - protected void innerExecute() { - this.permittedProviderType = - (permittedProviderTypes == null || permittedProviderTypes.isBlank()) - ? ApplicationCreatorConfigOptions.DEFAULT_PERMITTED_PROVIDER_TYPE - : PermittedProviderType.valueOf(permittedProviderTypes.toUpperCase()); - - CallingContext callCtx = null; - Optional callingContextBuilder = - CallingContextFactory.createBuilder(false); - if (callingContextBuilder.isPresent()) { - callingContextBuilder.get() - .update(it -> Optional.ofNullable(getThisModuleName()).ifPresent(it::moduleName)); - callCtx = callingContextBuilder.get().build(); - globalCallingContext(callCtx, true); - } - - // we MUST get the exclusion list prior to building the next loader, since it will reset the service registry - Set serviceNamesForExclusion = getServiceTypeNamesForExclusion(); - boolean hasModuleInfo = hasModuleInfo(); - Set modulepath = (hasModuleInfo) ? getModulepathElements() : Collections.emptySet(); - Set classpath = getClasspathElements(); - ClassLoader prev = Thread.currentThread().getContextClassLoader(); - URLClassLoader loader = ExecutableClassLoader.create(classpath, prev); - - try { - Thread.currentThread().setContextClassLoader(loader); - - InjectionServices injectionServices = MavenPluginUtils.injectionServices(false); - if (injectionServices.config().usesCompileTimeApplications()) { - String desc = "Should not be using 'application' bindings"; - String msg = (callCtx == null) ? toErrorMessage(desc) : toErrorMessage(callCtx, desc); - throw new IllegalStateException(msg); - } - Services services = injectionServices.services(); - - // get the application creator only after services are initialized (we need to ignore any existing apps) - ApplicationCreator creator = MavenPluginUtils.applicationCreator(); - - List> allModules = services - .lookupAll(ServiceInfoCriteria.builder() - .addContractImplemented(ModuleComponent.class) - .build()); - if (InjectionServices.isDebugEnabled()) { - getLog().info("processing modules: " + MavenPluginUtils.toDescriptions(allModules)); - } else { - getLog().debug("processing modules: " + MavenPluginUtils.toDescriptions(allModules)); - } - if (allModules.isEmpty()) { - warn("No modules to process"); - } - - // retrieves all the services in the registry - List> allServices = services - .lookupAll(ServiceInfoCriteria.builder() - .includeIntercepted(true) - .build(), false); - if (allServices.isEmpty()) { - warn("no services to process"); - return; - } - - Set serviceTypeNames = toNames(allServices); - serviceTypeNames.removeAll(serviceNamesForExclusion); - - String classPrefixName = getClassPrefixName(); - AtomicReference moduleInfoPathRef = new AtomicReference<>(); - ModuleInfoDescriptor descriptor = getAnyModuleInfo(moduleInfoPathRef); - String moduleInfoPath = (moduleInfoPathRef.get() != null) - ? moduleInfoPathRef.get().getPath() - : null; - String moduleInfoModuleName = getThisModuleName(); - Optional> moduleSp = lookupThisModule(moduleInfoModuleName, services, false); - String packageName = determinePackageName(moduleSp, serviceTypeNames, descriptor, true); - - CodeGenPaths codeGenPaths = CodeGenPaths.builder() - .generatedSourcesPath(getGeneratedSourceDirectory().getPath()) - .outputPath(getOutputDirectory().getPath()) - .update(it -> ofNullable(moduleInfoPath).ifPresent(it::moduleInfoPath)) - .build(); - ApplicationCreatorCodeGen applicationCodeGen = ApplicationCreatorCodeGen.builder() - .packageName(packageName) - .className(getGeneratedClassName()) - .classPrefixName(classPrefixName) - .build(); - List compilerArgs = getCompilerArgs(); - CompilerOptions compilerOptions = CompilerOptions.builder() - .classpath(List.copyOf(classpath)) - .modulepath(List.copyOf(modulepath)) - .sourcepath(getSourceRootPaths()) - .source(getSource()) - .target(getTarget()) - .commandLineArguments((compilerArgs != null) ? compilerArgs : List.of()) - .build(); - ApplicationCreatorConfigOptions configOptions = ApplicationCreatorConfigOptions.builder() - .permittedProviderTypes(permittedProviderType) - .permittedProviderNames(Set.copyOf(permittedProviderTypeNames)) - .permittedProviderQualifierTypeNames(Set.copyOf(toTypeNames(permittedProviderQualifierTypeNames))) - .build(); - String moduleName = getModuleName(); - AbstractFilerMessager directFiler = AbstractFilerMessager.createDirectFiler(codeGenPaths, getLogger()); - CodeGenFiler codeGenFiler = CodeGenFiler.create(directFiler); - ApplicationCreatorRequest.Builder reqBuilder = ApplicationCreatorRequest.builder() - .codeGen(applicationCodeGen) - .messager(new Messager2LogAdapter()) - .filer(codeGenFiler) - .configOptions(configOptions) - .serviceTypeNames(List.copyOf(serviceTypeNames)) - .generatedServiceTypeNames(List.copyOf(serviceTypeNames)) - .codeGenPaths(codeGenPaths) - .compilerOptions(compilerOptions) - .throwIfError(isFailOnError()) - .generator(getClass().getName()) - .templateName(getTemplateName()); - if (MavenPluginUtils.hasValue(moduleName)) { - reqBuilder.moduleName(moduleName); - } else if (!isUnnamedModuleName(moduleInfoModuleName)) { - reqBuilder.moduleName(moduleInfoModuleName); - } - ApplicationCreatorRequest req = reqBuilder.build(); - ApplicationCreatorResponse res = creator.createApplication(req); - if (res.success()) { - getLog().debug("processed service type names: " + res.serviceTypeNames()); - if (getLog().isDebugEnabled()) { - getLog().debug("response: " + res); - } - } else { - getLog().error("failed to process", res.error().orElse(null)); - } - } catch (Exception e) { - throw new ToolsException("An error occurred creating the Application in " + getClass().getName(), e); - } finally { - Thread.currentThread().setContextClassLoader(prev); - } - } - - List toTypeNames(List permittedProviderQualifierTypeNames) { - if (permittedProviderQualifierTypeNames == null || permittedProviderQualifierTypeNames.isEmpty()) { - return List.of(); - } - - return permittedProviderQualifierTypeNames.stream() - .map(TypeName::create) - .collect(Collectors.toList()); - } - - Set toNames(List> services) { - Map> result = new LinkedHashMap<>(); - services.forEach(sp -> { - sp = ServiceBinderDefault.toRootProvider(sp); - TypeName serviceType = sp.serviceInfo().serviceTypeName(); - ServiceProvider prev = result.put(serviceType, sp); - if (prev != null) { - if (!(prev instanceof ServiceProviderProvider)) { - throw new ToolsException("There are two registrations for the same service type: " + prev + " and " + sp); - } - getLog().debug("There are two registrations for the same service type: " + prev + " and " + sp); - } - }); - return new TreeSet<>(result.keySet()); - } - - void warn(String msg) { - Optional optBuilder = CallingContextFactory.createBuilder(false); - CallingContext callCtx = optBuilder.map(builder -> builder - .update(it -> Optional.ofNullable(getThisModuleName()).ifPresent(it::moduleName))) - .map(CallingContext.Builder::build) - .orElse(null); - String desc = "no modules to process"; - String ctxMsg = (callCtx == null) ? toErrorMessage(desc) : toErrorMessage(callCtx, desc); - ToolsException e = new ToolsException(ctxMsg); - if (InjectionServices.isDebugEnabled()) { - getLog().warn(e.getMessage(), e); - } else { - getLog().warn(e.getMessage()); - } - if (isFailOnWarning()) { - throw e; - } - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractCreatorMojo.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractCreatorMojo.java deleted file mode 100644 index e1a5c366cae..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractCreatorMojo.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.io.File; -import java.nio.file.Path; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Optional; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.tools.AbstractCreator; -import io.helidon.inject.tools.Messager; -import io.helidon.inject.tools.ModuleInfoDescriptor; -import io.helidon.inject.tools.ModuleUtils; -import io.helidon.inject.tools.Options; -import io.helidon.inject.tools.TemplateHelper; -import io.helidon.inject.tools.ToolsException; - -import org.apache.maven.artifact.Artifact; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.MavenProject; - -import static io.helidon.inject.tools.ModuleUtils.toSuggestedGeneratedPackageName; - -/** - * Abstract base for all creator mojo's. - */ -@SuppressWarnings({"unused", "FieldCanBeLocal", "FieldMayBeFinal"}) -public abstract class AbstractCreatorMojo extends AbstractMojo { - private final System.Logger logger = System.getLogger(getClass().getName()); - - static final String DEFAULT_SOURCE = AbstractCreator.DEFAULT_SOURCE; - static final String DEFAULT_TARGET = AbstractCreator.DEFAULT_TARGET; - - static final TrafficCop TRAFFIC_COP = new TrafficCop(); - - /** - * Tag controlling whether we fail on error. - */ - static final String TAG_FAIL_ON_ERROR = "inject.failOnError"; - - /** - * Tag controlling whether we fail on warnings. - */ - static final String TAG_FAIL_ON_WARNING = "inject.failOnWarning"; - - static final String TAG_PACKAGE_NAME = "inject.package.name"; - - /** - * The file name written to ./target/inject/ to track the last package name generated for this application. - * This application package name is what we fall back to for the application name and the module name if not otherwise - * specified directly. - */ - protected static final String APPLICATION_PACKAGE_FILE_NAME = ModuleUtils.APPLICATION_PACKAGE_FILE_NAME; - - // ---------------------------------------------------------------------- - // Configurables - // ---------------------------------------------------------------------- - - /** - * The template name to use for codegen. - */ - @Parameter(property = TemplateHelper.TAG_TEMPLATE_NAME, readonly = true, defaultValue = TemplateHelper.DEFAULT_TEMPLATE_NAME) - private String templateName; - - /** - * The module name to apply. If not found the module name will be inferred. - */ - @Parameter(property = Options.TAG_MODULE_NAME, readonly = true) - private String moduleName; - - // ---------------------------------------------------------------------- - // Generic Configurables - // ---------------------------------------------------------------------- - - /** - * The current project instance. This is used for propagating generated-sources paths as - * compile/testCompile source roots. - */ - @Parameter(defaultValue = "${project}", readonly = true, required = true) - private MavenProject project; - - /** - * Indicates whether the build will continue even if there are compilation errors. - */ - @Parameter(property = TAG_FAIL_ON_ERROR, defaultValue = "true") - private boolean failOnError = true; - - /** - * Indicates whether the build will continue even if there are any warnings. - */ - @Parameter(property = TAG_FAIL_ON_WARNING) - private boolean failOnWarning; - - /** - * The -source argument for the Java compiler. - * Note: using the same as maven-compiler for convenience and least astonishment. - */ - @Parameter(property = "maven.compiler.source", defaultValue = DEFAULT_SOURCE) - private String source; - - /** - * The -target argument for the Java compiler. - * Note: using the same as maven-compiler for convenience and least astonishment. - */ - @Parameter(property = "maven.compiler.target", defaultValue = DEFAULT_TARGET) - private String target; - - /** - * The target directory where to place output. - */ - @Parameter(defaultValue = "${project.build.directory}", readonly = true) - private String targetDir; - - /** - * The package name to apply. If not found the package name will be inferred. - */ - @Parameter(property = TAG_PACKAGE_NAME, readonly = true) - private String packageName; - - /** - * Sets the arguments to be passed to the compiler. - *

- * Example: - *

-     * <compilerArgs>
-     *   <arg>-Xmaxerrs</arg>
-     *   <arg>1000</arg>
-     *   <arg>-Xlint</arg>
-     *   <arg>-J-Duser.language=en_us</arg>
-     * </compilerArgs>
-     * 
- */ - @Parameter - private List compilerArgs; - - /** - * Sets the debug flag. - * See {@link InjectionServices#TAG_DEBUG}. - */ - @Parameter(property = InjectionServices.TAG_DEBUG, readonly = true) - private boolean isDebugEnabled; - - /** - * Default constructor. - */ - protected AbstractCreatorMojo() { - } - - /** - * Returns true if debug is enabled. - * - * @return true if in debug mode - */ - protected boolean isDebugEnabled() { - return isDebugEnabled; - } - - /** - * The project build directory. - * - * @return the project build directory - */ - protected File getProjectBuildTargetDir() { - return new File(targetDir); - } - - /** - * The scratch directory. - * - * @return the scratch directory - */ - protected File getInjectScratchDir() { - return new File(getProjectBuildTargetDir(), "inject"); - } - - /** - * The target package name. - * - * @return the target package name - */ - protected String getPackageName() { - return packageName; - } - - System.Logger getLogger() { - return logger; - } - - String getTemplateName() { - return templateName; - } - - String getModuleName() { - return moduleName; - } - - MavenProject getProject() { - return project; - } - - boolean isFailOnError() { - return failOnError; - } - - boolean isFailOnWarning() { - return failOnWarning; - } - - String getSource() { - return source; - } - - String getTarget() { - return target; - } - - List getCompilerArgs() { - return compilerArgs; - } - - @Override - public void execute() throws MojoExecutionException { - try (TrafficCop.GreenLight greenLight = TRAFFIC_COP.waitForGreenLight()) { - getLog().info("Started " + getClass().getName() + " for " + getProject()); - innerExecute(); - getLog().info("Finishing " + getClass().getName() + " for " + getProject()); - MavenPluginUtils.resetAll(); - } catch (Throwable t) { - MojoExecutionException me = new MojoExecutionException("Injection maven-plugin execution failed", t); - getLog().error(me.getMessage(), t); - throw me; - } finally { - getLog().info("Finished " + getClass().getName() + " for " + getProject()); - } - } - - /** - * Determines the primary package name (which also typically doubles as the application name). - * - * @param optModuleSp the module service provider - * @param typeNames the type names - * @param descriptor the descriptor - * @param persistIt pass true to write it to scratch, so that we can use it in the future for this module - * @return the package name (which also typically doubles as the application name) - */ - protected String determinePackageName(Optional> optModuleSp, - Collection typeNames, - ModuleInfoDescriptor descriptor, - boolean persistIt) { - String packageName = getPackageName(); - if (packageName == null) { - // check for the existence of the file - packageName = loadAppPackageName().orElse(null); - if (packageName != null) { - return packageName; - } - - ServiceProvider moduleSp = optModuleSp.orElse(null); - if (moduleSp != null) { - packageName = moduleSp.serviceInfo().serviceTypeName().packageName(); - } else { - if (descriptor == null) { - packageName = toSuggestedGeneratedPackageName(typeNames, "inject"); - } else { - packageName = toSuggestedGeneratedPackageName(typeNames, "inject", descriptor); - } - } - } - - if (packageName == null || packageName.isBlank()) { - throw new ToolsException("Unable to determine the package name. The package name can be set using " - + TAG_PACKAGE_NAME); - } - - if (persistIt) { - // record it to scratch file for later consumption (during test build for example) - saveAppPackageName(packageName); - } - - return packageName; - } - - /** - * Attempts to load the app package name from what was previously recorded. - * - * @return the app package name that was loaded - */ - protected Optional loadAppPackageName() { - return ModuleUtils.loadAppPackageName(getInjectScratchDir().toPath()); - } - - /** - * Persist the package name into scratch for later usage. - * - * @param packageName the package name - */ - protected void saveAppPackageName(String packageName) { - ModuleUtils.saveAppPackageName(getInjectScratchDir().toPath(), packageName); - } - - /** - * Gated/controlled by the {@link TrafficCop}. - * - * @throws MojoExecutionException if any mojo problems occur - */ - protected abstract void innerExecute() throws MojoExecutionException; - - LinkedHashSet getDependencies(String optionalScopeFilter) { - MavenProject project = getProject(); - LinkedHashSet result = new LinkedHashSet<>(project.getDependencyArtifacts().size()); - for (Object a : project.getDependencyArtifacts()) { - Artifact artifact = (Artifact) a; - if (optionalScopeFilter == null || optionalScopeFilter.equals(artifact.getScope())) { - result.add(((Artifact) a).getFile().toPath()); - } - } - return result; - } - - LinkedHashSet getSourceClasspathElements() { - MavenProject project = getProject(); - LinkedHashSet result = new LinkedHashSet<>(project.getCompileArtifacts().size()); - result.add(new File(project.getBuild().getOutputDirectory()).toPath()); - for (Object a : project.getCompileArtifacts()) { - result.add(((Artifact) a).getFile().toPath()); - } - return result; - } - - /** - * Provides a convenient way to handle test scope. Returns the classpath for source files (or test sources) only. - */ - LinkedHashSet getClasspathElements() { - return getSourceClasspathElements(); - } - - abstract File getGeneratedSourceDirectory(); - - - class Messager2LogAdapter implements Messager { - @Override - public void debug(String message) { - getLog().debug(message); - } - - @Override - public void debug(String message, - Throwable t) { - getLog().debug(message, t); - } - - @Override - public void log(String message) { - getLog().info(message); - } - - @Override - public void warn(String message) { - getLog().warn(message); - } - - @Override - public void warn(String message, - Throwable t) { - getLog().warn(message, t); - } - - @Override - public void error(String message, - Throwable t) { - getLog().error(message, t); - } - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ApplicationCreatorMojo.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ApplicationCreatorMojo.java deleted file mode 100644 index 0a1f5ffe970..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ApplicationCreatorMojo.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.io.File; - -import io.helidon.inject.api.Application; -import io.helidon.inject.tools.ApplicationCreatorDefault; -import io.helidon.inject.tools.spi.ApplicationCreator; - -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; - -/** - * A mojo wrapper to {@link ApplicationCreator}. - */ -@Mojo(name = "application-create", defaultPhase = LifecyclePhase.COMPILE, threadSafe = true, - requiresDependencyResolution = ResolutionScope.COMPILE) -@SuppressWarnings("unused") -public class ApplicationCreatorMojo extends AbstractApplicationCreatorMojo { - - /** - * The classname to use for the {@link Application} class. - * If not found the classname will be inferred. - */ - @Parameter(property = "inject.application.class.name", readonly = true) - private String className; - - /** - * Specify where to place generated source files created by annotation processing. - */ - @Parameter(defaultValue = "${project.build.directory}/generated-sources/annotations") - private File generatedSourcesDirectory; - - /** - * The directory for compiled classes. - */ - @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true) - private File outputDirectory; - - /** - * Default constructor. - */ - public ApplicationCreatorMojo() { - } - - @Override - String getGeneratedClassName() { - return (className == null) ? ApplicationCreatorDefault.APPLICATION_NAME : className; - } - - @Override - File getGeneratedSourceDirectory() { - return generatedSourcesDirectory; - } - - @Override - File getOutputDirectory() { - return outputDirectory; - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExecHandler.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExecHandler.java deleted file mode 100644 index 4a7302c8ebe..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExecHandler.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.io.Closeable; -import java.io.IOException; -import java.net.URLClassLoader; -import java.util.Objects; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.function.Supplier; - -import io.helidon.inject.tools.ToolsException; - -/** - * Delegates a functional invocation to be run within the context of a provided ClassLoader. - */ -class ExecHandler implements Closeable { - private final boolean ownedContext; - private final IsolatedThreadGroup threadGroup; - private final URLClassLoader loader; - - /** - * Creates an instance using the provided threadGroup and loader. - * - * @param threadGroup the containing thread group to use for any/all spawned threads. - * @param loader the loader context to invoke the function in - */ - ExecHandler(boolean ownedContext, - IsolatedThreadGroup threadGroup, - URLClassLoader loader) { - this.ownedContext = ownedContext; - this.threadGroup = threadGroup; - this.loader = loader; - } - - /** - * Creates an instance using the provided threadGroup and loader. The caller is responsible - * for the lifecycle and closure of the provided context elements. - * - * @param threadGroup the containing thread group to use for any/all spawned threads - * @param loader the loader context to invoke the function - * @return the exec handler instance - */ - static ExecHandler create(IsolatedThreadGroup threadGroup, - URLClassLoader loader) { - return new ExecHandler(false, Objects.requireNonNull(threadGroup), Objects.requireNonNull(loader)); - } - - /** - * Creates a new dedicated thread for each invocation, running within the context of the provided - * isolated thread group and loader. If the request supplier returns null, then that is the signal - * to the implementation to abort the function call. - * - * @param reqSupplier the request supplier (obviously loaded in the caller's thread context/loader) - * @param fn the function to call (obviously loaded in the caller's thread/context loader) - * @param the function request type - * @param the function response type - * @return res the result (where the caller might have to use reflection to access) - */ - Res apply(Supplier reqSupplier, - Function fn) { - CountDownLatch latch = new CountDownLatch(1); - AtomicReference result = new AtomicReference<>(); - - Thread bootstrapThread = new Thread(threadGroup, () -> { - try { - Req req = reqSupplier.get(); - if (req == null) { - return; - } - result.set(fn.apply(req)); - } catch (Throwable t) { - throw new ToolsException("An error occurred in apply", t); - } finally { - latch.countDown(); - } - }); - threadGroup.preStart(bootstrapThread, loader); - bootstrapThread.start(); - - try { - latch.await(); - } catch (InterruptedException e) { - throw new ToolsException(e.getMessage(), e); - } - - threadGroup.throwAnyUncaughtErrors(); - - return result.get(); - } - - /** - * Should be closed to clean up any owned/acquired resources. - */ - @Override - public void close() throws IOException { - if (ownedContext) { - threadGroup.close(); - loader.close(); - } - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExecutableClassLoader.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExecutableClassLoader.java deleted file mode 100644 index cd0b2bd48be..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExecutableClassLoader.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import io.helidon.inject.tools.ToolsException; - -/** - * Responsible for creating a spi classlaoder using a child-first delegation strategy that can - * handle execution of callables, etc. using it. - */ - class ExecutableClassLoader { - private ExecutableClassLoader() { - } - - /** - * Creates the loader appropriate for {@link ExecHandler}. - * - * @param classPath the classpath to use - * @param parent the parent loader - * @return the loader - */ - public static URLClassLoader create(Collection classPath, - ClassLoader parent) { - List urls = new ArrayList<>(classPath.size()); - try { - for (Path dependency : classPath) { - urls.add(dependency.toUri().toURL()); - } - } catch (MalformedURLException e) { - throw new ToolsException("Unable to build the classpath", e); - } - - if (parent == null) { - parent = Thread.currentThread().getContextClassLoader(); - } - return new URLClassLoader(urls.toArray(new URL[0]), parent); - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExternalModuleCreatorMojo.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExternalModuleCreatorMojo.java deleted file mode 100644 index 323b5ba5f4f..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ExternalModuleCreatorMojo.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.io.File; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.tools.AbstractFilerMessager; -import io.helidon.inject.tools.ActivatorCreatorConfigOptions; -import io.helidon.inject.tools.ActivatorCreatorRequest; -import io.helidon.inject.tools.ActivatorCreatorResponse; -import io.helidon.inject.tools.CodeGenFiler; -import io.helidon.inject.tools.CodeGenPaths; -import io.helidon.inject.tools.ExternalModuleCreatorRequest; -import io.helidon.inject.tools.ExternalModuleCreatorResponse; -import io.helidon.inject.tools.spi.ActivatorCreator; -import io.helidon.inject.tools.spi.ExternalModuleCreator; - -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; - -import static io.helidon.inject.maven.plugin.MavenPluginUtils.activatorCreator; -import static io.helidon.inject.maven.plugin.MavenPluginUtils.externalModuleCreator; - -/** - * Responsible for creating {@link Activator}'s and a {@link ModuleComponent} - * wrapping a set of packages from an external third-party jar. - */ -@Mojo(name = "external-module-create", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true, - requiresDependencyResolution = ResolutionScope.COMPILE) -@SuppressWarnings("unused") -public class ExternalModuleCreatorMojo extends AbstractCreatorMojo { - - /** - * Sets the packages to be passed to the creator. - *

- * Example: - *

-     * <packageNames>
-     *   <org.inject.tck.auto>
-     *   <org.inject.tck.auto.accessories>
-     * </packageNames>
-     * 
- */ - @Parameter(required = true) - private List packageNames; - - /** - * Sets the qualifiers to be passed to the creator. - *

- * Example: - *

-     * <serviceTypeToQualifiers>
-     *   <org.atinject.tck.auto.accessories.SpareTire>
-     *   <qualifier>
-     *      <qualifierTypeName>
-     *      </qualifierTypeName>
-     *      <value>
-     *      </value>
-     *   </qualifier>
-     *   </org.atinject.tck.auto.accessories.SpareTire>
-     * </serviceTypeToQualifiers>
-     * 
- */ - @Parameter(name = "serviceTypeQualifiers") - private List serviceTypeQualifiers; - - /** - * Establishes whether strict jsr-330 compliance is in effect. - */ - @Parameter(name = "supportsJsr330Strict", property = "inject.supports-jsr330.strict") - private boolean supportsJsr330Strict; - - /** - * Specify where to place generated source files created by annotation processing. - */ - @Parameter(defaultValue = "${project.build.directory}/generated-sources/inject") - private File generatedSourcesDirectory; - - /** - * Default constructor. - */ - public ExternalModuleCreatorMojo() { - } - - /** - * @return the package names that should be targeted for activator creation - */ - List getPackageNames() { - return packageNames; - } - - /** - * @return the explicit qualifiers that should be setup as part of activator creation - */ - Map> getServiceTypeToQualifiers() { - if (serviceTypeQualifiers == null) { - return Map.of(); - } - - Map> result = new LinkedHashMap<>(); - serviceTypeQualifiers.forEach((serviceTypeQualifiers) -> result.putAll(serviceTypeQualifiers.toMap())); - return result; - } - - /** - * @return true if jsr-330 strict mode is in effect - */ - boolean isSupportsJsr330InStrictMode() { - return supportsJsr330Strict; - } - - /** - * @return the generated sources directory - */ - @Override - File getGeneratedSourceDirectory() { - return generatedSourcesDirectory; - } - - /** - * @return the output directory - */ - File getOutputDirectory() { - return new File(getProject().getBuild().getOutputDirectory()); - } - - @Override - protected void innerExecute() throws MojoExecutionException { - if (packageNames == null || packageNames.isEmpty()) { - throw new MojoExecutionException("packageNames are required to be specified"); - } - - ClassLoader prev = Thread.currentThread().getContextClassLoader(); - Set classpath = getDependencies("compile"); - URLClassLoader loader = ExecutableClassLoader.create(classpath, prev); - - try { - Thread.currentThread().setContextClassLoader(loader); - - ExternalModuleCreator externalModuleCreator = externalModuleCreator(); - - ActivatorCreatorConfigOptions configOptions = ActivatorCreatorConfigOptions.builder() - .supportsJsr330InStrictMode(isSupportsJsr330InStrictMode()) - .build(); - String generatedSourceDir = getGeneratedSourceDirectory().getPath(); - - CodeGenPaths codeGenPaths = CodeGenPaths.builder() - .generatedSourcesPath(generatedSourceDir) - .outputPath(getOutputDirectory().getPath()) - .metaInfServicesPath(new File(getOutputDirectory(), "META-INF/services").getPath()) - .build(); - AbstractFilerMessager directFiler = AbstractFilerMessager.createDirectFiler(codeGenPaths, getLogger()); - CodeGenFiler codeGenFiler = CodeGenFiler.create(directFiler); - ExternalModuleCreatorRequest request = ExternalModuleCreatorRequest.builder() - .packageNamesToScan(getPackageNames()) - .serviceTypeToQualifiersMap(getServiceTypeToQualifiers()) - .throwIfError(isFailOnWarning()) - .activatorCreatorConfigOptions(configOptions) - .codeGenPaths(codeGenPaths) - .update(it -> Optional.ofNullable(getModuleName()).ifPresent(it::moduleName)) - .filer(codeGenFiler) - .build(); - ExternalModuleCreatorResponse res = externalModuleCreator.prepareToCreateExternalModule(request); - if (res.success()) { - getLog().debug("processed service type names: " + res.serviceTypeNames()); - if (getLog().isDebugEnabled()) { - getLog().debug("response: " + res); - } - - // now proceed to creating the activators (we get this from the external module creation) - ActivatorCreatorRequest activatorCreatorRequest = res.activatorCreatorRequest(); - ActivatorCreator activatorCreator = activatorCreator(); - ActivatorCreatorResponse activatorCreatorResponse = - activatorCreator.createModuleActivators(activatorCreatorRequest); - if (activatorCreatorResponse.success()) { - getProject().addCompileSourceRoot(generatedSourceDir); - getLog().info("successfully processed: " + activatorCreatorResponse.serviceTypeNames()); - } else { - getLog().error("failed to process", activatorCreatorResponse.error().orElse(null)); - } - } else { - getLog().error("failed to process", res.error().orElse(null)); - } - } finally { - Thread.currentThread().setContextClassLoader(prev); - } - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/IsolatedThreadGroup.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/IsolatedThreadGroup.java deleted file mode 100644 index ef77b437b8e..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/IsolatedThreadGroup.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.inject.tools.ToolsException; - -/** - * a ThreadGroup to isolate execution and collect exceptions. - */ -class IsolatedThreadGroup extends ThreadGroup implements Closeable { - static final long DEFAULT_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(20); - - private final AtomicInteger counter = new AtomicInteger(); - private final long timeoutInMillis; - private Throwable uncaughtThrowable; - - private IsolatedThreadGroup(String name, - long timeOutInMillis) { - super(name); - this.timeoutInMillis = timeOutInMillis; - } - - /** - * Creates am isolated thread group using the default timeout of {@link #DEFAULT_TIMEOUT_MILLIS}. - * - * @param name the name of the group - * @return the instance of the isolated thread group created - */ - static IsolatedThreadGroup create(String name) { - return new IsolatedThreadGroup(name, DEFAULT_TIMEOUT_MILLIS); - } - - /** - * Creates an isolated thread group using the provided timeout of {@link #DEFAULT_TIMEOUT_MILLIS}. - * - * @param name the name of the group - * @param timeOutInMillis timeoutInMillis used during close processing - * @return the instance of the isolated thread group created - */ - static IsolatedThreadGroup create(String name, - long timeOutInMillis) { - return new IsolatedThreadGroup(name, timeOutInMillis); - } - - /** - * Adds an uncaught throwable for this thread group. - * - * @param t the throwable to add, or null to reset - */ - void setUncaughtThrowable(Throwable t) { - if (t instanceof ThreadDeath) { - return; // harmless - } - if (uncaughtThrowable != null) { - // we will only handle 0..1 errors - return; - } - this.uncaughtThrowable = t; - } - - /** - * Should be closed at completion. The implementation will attempt to join threads, - * terminate any threads after the timeout period, and throw any uncaught errors. - */ - @Override - public void close() { - try { - joinNonDaemonThreads(); - terminateThreads(); - } catch (Throwable t) { - setUncaughtThrowable(t); - } - throwAnyUncaughtErrors(); - } - - /** - * If anything was caught, will throw an error immediately. - */ - public void throwAnyUncaughtErrors() { - if (uncaughtThrowable != null) { - ToolsException e = new ToolsException("uncaught error", uncaughtThrowable); - uncaughtThrowable = null; - throw e; - } - } - - /** - * Prepares the thread for start. - * - * @param thread the thread - * @param loader the loader - */ - void preStart(Thread thread, - ClassLoader loader) { - thread.setContextClassLoader(loader); - thread.setName(getName() + "-" + counter.incrementAndGet()); - } - - private void joinNonDaemonThreads() { - boolean foundNonDaemon; - long expiry = System.currentTimeMillis() + timeoutInMillis; - do { - foundNonDaemon = false; - Collection threads = getActiveThreads(); - for (Thread thread : threads) { - if (thread.isDaemon()) { - continue; - } - // try again; maybe more threads were created while we are busy - foundNonDaemon = true; - joinThread(thread, 0); - } - } while (foundNonDaemon && System.currentTimeMillis() < expiry); - } - - private void joinThread(Thread thread, - long timeoutInMillis) { - try { - thread.join(timeoutInMillis); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - private void terminateThreads() { - // these were not responsive to interruption - Set uncooperativeThreads = new CopyOnWriteArraySet<>(); - - getActiveThreads().parallelStream().forEach(thread -> { - thread.interrupt(); - if (thread.isAlive()) { - joinThread(thread, timeoutInMillis); - if (thread.isAlive()) { - uncooperativeThreads.add(thread); - } - } - }); - - if (!uncooperativeThreads.isEmpty()) { - uncaughtThrowable = new ToolsException("unable to terminate these threads: " + uncooperativeThreads); - } - } - - /** - * Returns the list of threads for this thread group. - * - * @return list of threads - */ - List getActiveThreads() { - Thread[] threads = new Thread[activeCount()]; - int numThreads = enumerate(threads); - List result = new ArrayList<>(numThreads); - for (int i = 0; i < threads.length && threads[i] != null; i++) { - result.add(threads[i]); - } - return result; - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/MavenPluginUtils.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/MavenPluginUtils.java deleted file mode 100644 index 9173eaedea1..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/MavenPluginUtils.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.stream.Collectors; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.common.LazyValue; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesHolder; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.configdriven.runtime.ConfigBeanRegistry; -import io.helidon.inject.tools.spi.ActivatorCreator; -import io.helidon.inject.tools.spi.ApplicationCreator; -import io.helidon.inject.tools.spi.ExternalModuleCreator; - -final class MavenPluginUtils { - private MavenPluginUtils() { - } - - /** - * Returns a {@link Services} registry that forces application loading to be disabled. - * - * @return injection services - */ - static InjectionServices injectionServices(boolean wantApps) { - resetAll(); - return lazyCreate(basicConfig(wantApps)).get(); - } - - /** - * Resets all internal Injection configuration instances, JVM global singletons, service registries, etc. - */ - static void resetAll() { - Internal.reset(); - } - - static ApplicationCreator applicationCreator() { - return HelidonServiceLoader.create(ServiceLoader.load(ApplicationCreator.class)).iterator().next(); - } - - static ExternalModuleCreator externalModuleCreator() { - return HelidonServiceLoader.create(ServiceLoader.load(ExternalModuleCreator.class)).iterator().next(); - } - - static ActivatorCreator activatorCreator() { - return HelidonServiceLoader.create(ServiceLoader.load(ActivatorCreator.class)).iterator().next(); - } - - /** - * Describe the provided instance or provider. - * - * @param providerOrInstance the instance to provider - * @return the description of the instance - */ - static String toDescription(Object providerOrInstance) { - if (providerOrInstance instanceof Optional) { - providerOrInstance = ((Optional) providerOrInstance).orElse(null); - } - - if (providerOrInstance instanceof ServiceProvider) { - return ((ServiceProvider) providerOrInstance).description(); - } - return String.valueOf(providerOrInstance); - } - - /** - * Describe the provided instance or provider collection. - * - * @param coll the instance to provider collection - * @return the description of the instance - */ - static List toDescriptions(Collection coll) { - return coll.stream().map(MavenPluginUtils::toDescription).collect(Collectors.toList()); - } - - static boolean hasValue(String val) { - return (val != null && !val.isBlank()); - } - - static LazyValue lazyCreate(Config config) { - return LazyValue.create(() -> { - InjectionServices.globalBootstrap(Bootstrap.builder() - .config(config) - .limitRuntimePhase(Phase.GATHERING_DEPENDENCIES) - .build()); - return InjectionServices.injectionServices().orElseThrow(); - }); - } - - static Config basicConfig(boolean apps) { - return Config.builder(ConfigSources.create( - Map.of("inject.permits-dynamic", "true", - "inject.uses-compile-time-applications", String.valueOf(apps)), - "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - } - - private static class Internal extends InjectionServicesHolder { - public static void reset() { - InjectionServicesHolder.reset(); - ConfigBeanRegistry cbr = ConfigBeanRegistry.instance(); - if (cbr instanceof Resettable resettable) { - resettable.reset(true); - } - } - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/QualifierConfig.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/QualifierConfig.java deleted file mode 100644 index 454cdcad0e8..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/QualifierConfig.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Qualifier; - -/** - * Used by {@link ExternalModuleCreatorMojo}, and here in this package due to maven - * requirements to be in the same package as the mojo. - * See https://maven.apache.org/guides/mini/guide-configuring-plugins.html#Mapping_Complex_Objects - */ -public class QualifierConfig implements Qualifier { - private String qualifierTypeName; - private String value; - - /** - * Default constructor. - */ - public QualifierConfig() { - } - - @Override - public String qualifierTypeName() { - return qualifierTypeName; - } - - /** - * Sets the qualifier type name. - * - * @param val the qualifier type name - */ - public void setQualifierTypeName(String val) { - this.qualifierTypeName = val; - } - - @Override - public TypeName typeName() { - return TypeName.create(qualifierTypeName); - } - - @Override - public Optional value() { - return Optional.ofNullable(value); - } - - @Override - public Optional getValue(String property) { - throw new UnsupportedOperationException(); - } - - @Override - public Map values() { - if (value == null) { - return Map.of(); - } - return Map.of("value", value); - } - - @Override - public List metaAnnotations() { - return List.of(); - } - - @Override - public int compareTo(Annotation o) { - return this.typeName().compareTo(o.typeName()); - } - - @Override - public int hashCode() { - return Objects.hash(typeName(), values()); - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof Qualifier other)) { - return false; - } - return Objects.equals(typeName(), other.typeName()) && Objects.equals(values(), other.values()); - } - - /** - * Sets the qualifier value. - * - * @param val the qualifer value - */ - @SuppressWarnings("unused") - public void setValue(String val) { - this.value = val; - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ServiceTypeQualifiers.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ServiceTypeQualifiers.java deleted file mode 100644 index 25be0ec6b22..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/ServiceTypeQualifiers.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import io.helidon.inject.api.Qualifier; - -import org.apache.maven.plugins.annotations.Parameter; - -/** - * Used in {@link ExternalModuleCreatorMojo}. - */ -public class ServiceTypeQualifiers { - /** - * The service type name these qualifiers apply to. - */ - @Parameter(name = "serviceTypeName") - private String serviceTypeName; - - @Parameter(name = "qualifiers") - private List qualifiers; - - /** - * Default constructor. - */ - public ServiceTypeQualifiers() { - } - - /** - * @return the map representation for this instance - */ - Map> toMap() { - return Map.of(Objects.requireNonNull(serviceTypeName), new LinkedHashSet<>(Objects.requireNonNull(qualifiers))); - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/TestApplicationCreatorMojo.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/TestApplicationCreatorMojo.java deleted file mode 100644 index 25bd8a30876..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/TestApplicationCreatorMojo.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.io.File; -import java.net.URLClassLoader; -import java.nio.file.Path; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.tools.spi.ApplicationCreator; - -import org.apache.maven.artifact.Artifact; -import org.apache.maven.model.Build; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; -import org.apache.maven.project.MavenProject; - -import static io.helidon.inject.maven.plugin.MavenPluginUtils.injectionServices; -import static io.helidon.inject.tools.ApplicationCreatorDefault.APPLICATION_NAME_SUFFIX; -import static io.helidon.inject.tools.ApplicationCreatorDefault.NAME_PREFIX; -import static io.helidon.inject.tools.ApplicationCreatorDefault.upperFirstChar; -import static io.helidon.inject.tools.ModuleUtils.toBasePath; -import static io.helidon.inject.tools.ModuleUtils.toSuggestedModuleName; - -/** - * A mojo wrapper to {@link ApplicationCreator} for test specific types. - */ -@Mojo(name = "test-application-create", defaultPhase = LifecyclePhase.TEST_COMPILE, threadSafe = true, - requiresDependencyResolution = ResolutionScope.TEST) -@SuppressWarnings("unused") -public class TestApplicationCreatorMojo extends AbstractApplicationCreatorMojo { - - /** - * The classname to use for the {@link Application} test class. - * If not found the classname will be inferred. - */ - @Parameter(property = "io.helidon.inject.application.class.name", readonly = true - // note: the default value handling doesn't work here for "$$"!! - // defaultValue = DefaultApplicationCreator.APPLICATION_NAME - ) - private String className; - - /** - * Specify where to place generated source files created by annotation processing. - * Only applies to JDK 1.6+ - */ - @Parameter(defaultValue = "${project.build.directory}/generated-test-sources/test-annotations") - private File generatedTestSourcesDirectory; - - /** - * The directory where compiled test classes go. - */ - @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true, readonly = true) - private File testOutputDirectory; - - /** - * Default constructor. - */ - public TestApplicationCreatorMojo() { - } - - @Override - File getGeneratedSourceDirectory() { - return generatedTestSourcesDirectory; - } - - @Override - File getOutputDirectory() { - return testOutputDirectory; - } - - @Override - List getSourceRootPaths() { - return getTestSourceRootPaths(); - } - - @Override - LinkedHashSet getClasspathElements() { - MavenProject project = getProject(); - LinkedHashSet result = new LinkedHashSet<>(project.getTestArtifacts().size()); - result.add(new File(project.getBuild().getTestOutputDirectory()).toPath()); - for (Object a : project.getTestArtifacts()) { - result.add(((Artifact) a).getFile().toPath()); - } - result.addAll(super.getClasspathElements()); - return result; - } - - @Override - LinkedHashSet getModulepathElements() { - return getClasspathElements(); - } - - @Override - String getThisModuleName() { - Build build = getProject().getBuild(); - Path basePath = toBasePath(build.getTestSourceDirectory()); - String moduleName = toSuggestedModuleName(basePath, Path.of(build.getTestOutputDirectory()), true).orElseThrow(); - return moduleName; - } - - @Override - String getGeneratedClassName() { - return (className == null) ? NAME_PREFIX + "Test" + APPLICATION_NAME_SUFFIX : className; - } - - @Override - String getClassPrefixName() { - return upperFirstChar("test"); - } - - /** - * Excludes everything from source main scope. - */ - @Override - Set getServiceTypeNamesForExclusion() { - Set classPath = getSourceClasspathElements(); - - ClassLoader prev = Thread.currentThread().getContextClassLoader(); - URLClassLoader loader = ExecutableClassLoader.create(classPath, prev); - - try { - Thread.currentThread().setContextClassLoader(loader); - - InjectionServices injectionServices = injectionServices(false); - assert (!injectionServices.config().usesCompileTimeApplications()); - Services services = injectionServices.services(); - - // retrieves all the services in the registry - List> allServices = services - .lookupAll(ServiceInfoCriteria.builder().build(), false); - Set serviceTypeNames = toNames(allServices); - getLog().debug("excluding service type names: " + serviceTypeNames); - return serviceTypeNames; - } finally { - Thread.currentThread().setContextClassLoader(prev); - } - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/TrafficCop.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/TrafficCop.java deleted file mode 100644 index 6c75001660e..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/TrafficCop.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.maven.plugin; - -import java.util.concurrent.Semaphore; -import java.util.concurrent.atomic.AtomicBoolean; - -import io.helidon.inject.tools.ToolsException; - -/** - * maven-plugins will be called on the same JVM on different mojo instances when maven is run in parallel mode. If you didn't know - * this then you know it now. ;-) - *

- * Since the framework is designed in traditional microprofile patterns - the JVM is the container for one app - this is a problem. - * In order to - * compensate for this, we apply a traffic cop to effectively serialize access to the mojo execute() method so that only one can - * run at a time. The code is negligible in terms of performance, and still allows for parallel builds to occur. - */ -class TrafficCop { - private final Semaphore semaphore; - - TrafficCop() { - this.semaphore = new Semaphore(1); - } - - GreenLight waitForGreenLight() { - try { - return new GreenLight(semaphore); - } catch (InterruptedException e) { - throw new ToolsException("interrupted", e); - } - } - - static class GreenLight implements AutoCloseable { - private final Semaphore semaphore; - private final AtomicBoolean closed = new AtomicBoolean(false); - - private GreenLight(Semaphore semaphore) throws InterruptedException { - this.semaphore = semaphore; - semaphore.acquire(); - } - - @Override - public void close() { - if (closed.compareAndSet(false, true)) { - semaphore.release(); - } - } - } - -} diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/package-info.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/package-info.java deleted file mode 100644 index 0dad536d79e..00000000000 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Internal tooling for the injection maven-plugin. - */ -package io.helidon.inject.maven.plugin; diff --git a/inject/maven-plugin/src/main/java/module-info.java b/inject/maven-plugin/src/main/java/module-info.java deleted file mode 100644 index 9da1fc76302..00000000000 --- a/inject/maven-plugin/src/main/java/module-info.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection maven-plugin module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.maven.plugin { - - requires io.helidon.builder.api; - requires io.helidon.common; - requires io.helidon.config; - requires io.helidon.inject.configdriven.runtime; - requires maven.artifact; - requires maven.model; - requires maven.plugin.annotations; - requires maven.plugin.api; - requires maven.project; - - requires transitive io.helidon.inject.tools; - - exports io.helidon.inject.maven.plugin; - - uses io.helidon.inject.tools.spi.ActivatorCreator; - uses io.helidon.inject.tools.spi.ApplicationCreator; - uses io.helidon.inject.tools.spi.ExternalModuleCreator; - -} diff --git a/inject/pom.xml b/inject/pom.xml deleted file mode 100644 index f4d6d3d8799..00000000000 --- a/inject/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - 4.0.0 - - io.helidon - helidon-project - 4.2.0-SNAPSHOT - - io.helidon.inject - helidon-inject-project - Helidon Injection Project - - pom - - - - true - - - - api - configdriven - tools - processor - maven-plugin - testing - runtime - - - - - tests - - tests - - - - diff --git a/inject/processor/README.md b/inject/processor/README.md deleted file mode 100644 index 5328707f2cc..00000000000 --- a/inject/processor/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# inject-processor - -This module provides *compile-time only* annotation processing, and is designed to look for javax/jakarta inject type annotations to then code-generate supporting DI activator source artifacts in support for your injection points and dependency model. It leverages the [tools module](../tools/README.md) to perform the necessary code generation when Injection annotations are found. - -## Usage - -In your pom.xml, add this plugin to be run as part of the compilation phase: -```pom.xml - - org.apache.maven.plugins - maven-compiler-plugin - - true - - - io.helidon.inject - helidon-inject-processor - ${helidon.version} - - - - -``` diff --git a/inject/processor/etc/spotbugs/exclude.xml b/inject/processor/etc/spotbugs/exclude.xml deleted file mode 100644 index 3c9897deaac..00000000000 --- a/inject/processor/etc/spotbugs/exclude.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/inject/processor/pom.xml b/inject/processor/pom.xml deleted file mode 100644 index f913bd65635..00000000000 --- a/inject/processor/pom.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-processor - Helidon Injection Processor - - - etc/spotbugs/exclude.xml - - - - - io.helidon.inject - helidon-inject-tools - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - org.mockito - mockito-core - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/ActiveProcessorUtils.java b/inject/processor/src/main/java/io/helidon/inject/processor/ActiveProcessorUtils.java deleted file mode 100644 index 990738d626e..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/ActiveProcessorUtils.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.io.File; -import java.net.URI; -import java.nio.file.Path; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Predicate; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Filer; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic; -import javax.tools.FileObject; -import javax.tools.StandardLocation; - -import io.helidon.common.processor.TypeInfoFactory; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.tools.Messager; -import io.helidon.inject.tools.ModuleInfoDescriptor; -import io.helidon.inject.tools.ModuleInfoOrdering; -import io.helidon.inject.tools.Options; -import io.helidon.inject.tools.ServicesToProcess; - -import static io.helidon.inject.processor.GeneralProcessorUtils.toPath; -import static io.helidon.inject.tools.ModuleUtils.REAL_MODULE_INFO_JAVA_NAME; -import static io.helidon.inject.tools.ModuleUtils.inferSourceOrTest; - -/** - * Carries methods that are relative only during active APT processing. - * - * @see GeneralProcessorUtils - */ -final class ActiveProcessorUtils implements Messager { - static final boolean MAYBE_ANNOTATIONS_CLAIMED_BY_THIS_PROCESSOR = false; - static final String TARGET_DIR = "/target/"; - static final String SRC_MAIN_JAVA_DIR = "/src/main/java"; - - private final System.Logger logger; - private final ProcessingEnvironment processingEnv; - private RoundEnvironment roundEnv; - - ActiveProcessorUtils(AbstractProcessor processor, - ProcessingEnvironment processingEnv) { - this.logger = System.getLogger(processor.getClass().getName()); - this.processingEnv = Objects.requireNonNull(processingEnv); - - Options.init(processingEnv); - debug("*** Processing " + processor.getClass().getSimpleName() + " ***"); - } - - @Override - public void debug(String message, - Throwable t) { - if (Options.isOptionEnabled(Options.TAG_DEBUG)) { - out(System.Logger.Level.DEBUG, Diagnostic.Kind.OTHER, message, t); - } - } - - @Override - public void debug(String message) { - if (Options.isOptionEnabled(Options.TAG_DEBUG)) { - out(System.Logger.Level.DEBUG, Diagnostic.Kind.OTHER, message, null); - } - } - - @Override - public void log(String message) { - if (Options.isOptionEnabled(Options.TAG_DEBUG)) { - out(System.Logger.Level.INFO, Diagnostic.Kind.NOTE, message, null); - } - } - - @Override - public void warn(String message, - Throwable t) { - out(System.Logger.Level.WARNING, Diagnostic.Kind.WARNING, message, t); - } - - @Override - public void warn(String message) { - out(System.Logger.Level.WARNING, Diagnostic.Kind.WARNING, message, null); - } - - @Override - public void error(String message, - Throwable t) { - out(System.Logger.Level.ERROR, Diagnostic.Kind.ERROR, message, null); - } - - void out(System.Logger.Level level, - Diagnostic.Kind kind, - String message, - Throwable t) { - if (logger.isLoggable(level)) { - logger.log(level, getClass().getSimpleName() + ": " + message, t); - } - - if (processingEnv != null && processingEnv.getMessager() != null) { - processingEnv.getMessager().printMessage(kind, message); - } - } - - /** - * Attempts to load the {@link ModuleInfoDescriptor} for the (src or test) module being processed. - * - * @param typeSuffix this function will populate this with an empty string for src and "test" for test - * @param moduleInfoFile this function will populate this with the file path to the module-info source file - * @param srcPath this function will populate this with the source path - * @return the module info descriptor if the module being processed has one available - */ - // note: Atomic here is merely a convenience as a pass-by-reference holder, no async is actually needed here - Optional thisModuleDescriptor(AtomicReference typeSuffix, - AtomicReference moduleInfoFile, - AtomicReference srcPath) { - return tryFindModuleInfoTheConventionalWay(StandardLocation.SOURCE_OUTPUT, typeSuffix, moduleInfoFile, srcPath) - .or(() -> tryFindModuleInfoTheConventionalWay(StandardLocation.SOURCE_PATH, typeSuffix, moduleInfoFile, srcPath)) - // attempt to retrieve from src/main/java if we can't recover to this point - .or(() -> tryFindModuleInfoTheUnconventionalWayFromSourceMain(moduleInfoFile, srcPath)); - } - - /** - * Determines the module being processed, and relays module-info information into the provided services to process. - * - * @param servicesToProcess the services to process instance - */ - void relayModuleInfoToServicesToProcess(ServicesToProcess servicesToProcess) { - // note: Atomic here is merely a convenience as a pass-by-reference holder, no async is actually needed here - AtomicReference typeSuffix = new AtomicReference<>(); - AtomicReference moduleInfoFile = new AtomicReference<>(); - AtomicReference srcPath = new AtomicReference<>(); - ModuleInfoDescriptor thisModuleDescriptor = thisModuleDescriptor(typeSuffix, moduleInfoFile, srcPath).orElse(null); - if (thisModuleDescriptor != null) { - servicesToProcess.lastKnownModuleInfoDescriptor(thisModuleDescriptor); - } else { - String thisModuleName = Options.getOption(Options.TAG_MODULE_NAME).orElse(null); - if (thisModuleName == null) { - servicesToProcess.clearModuleName(); - } else { - servicesToProcess.moduleName(thisModuleName); - } - } - if (typeSuffix.get() != null) { - servicesToProcess.lastKnownTypeSuffix(typeSuffix.get()); - } - if (srcPath.get() != null) { - servicesToProcess.lastKnownSourcePathBeingProcessed(srcPath.get().toPath()); - } - if (moduleInfoFile.get() != null) { - servicesToProcess.lastKnownModuleInfoFilePath(moduleInfoFile.get().toPath()); - } - } - - /** - * Converts the provided element and mirror into a {@link TypeInfo} structure. - * - * @param element the element of the target service - * @param isOneWeCareAbout a predicate filter that is used to determine the elements of particular interest (e.g., injectable) - * @return the type info for the target - */ - Optional toTypeInfo(TypeElement element, - Predicate isOneWeCareAbout) { - return TypeInfoFactory.create(processingEnv, element, isOneWeCareAbout); - } - - System.Logger.Level loggerLevel() { - return (Options.isOptionEnabled(Options.TAG_DEBUG)) ? System.Logger.Level.INFO : System.Logger.Level.DEBUG; - } - - RoundEnvironment roundEnv() { - return roundEnv; - } - - void roundEnv(RoundEnvironment roundEnv) { - this.roundEnv = roundEnv; - } - - // note: Atomic here is merely a convenience as a pass-by-reference holder, no async is actually needed here - private Optional tryFindModuleInfoTheUnconventionalWayFromSourceMain( - AtomicReference moduleInfoFile, - AtomicReference srcPath) { - if (srcPath != null && srcPath.get() != null && srcPath.get().getPath().contains(TARGET_DIR)) { - String path = srcPath.get().getPath(); - int pos = path.indexOf(TARGET_DIR); - path = path.substring(0, pos); - File srcRoot = new File(path, SRC_MAIN_JAVA_DIR); - File file = new File(srcRoot, REAL_MODULE_INFO_JAVA_NAME); - if (file.exists()) { - try { - return Optional.of( - ModuleInfoDescriptor.create(file.toPath(), ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS)); - } catch (Exception e) { - debug("unable to read source module-info.java from: " + srcRoot + "; " + e.getMessage(), e); - } - - if (moduleInfoFile != null) { - moduleInfoFile.set(file); - } - } - } - - debug("unable to find module-info.java from: " + srcPath); - return Optional.empty(); - } - - // note: Atomic here is merely a convenience as a pass-by-reference holder, no async is actually needed here - private Optional tryFindModuleInfoTheConventionalWay(StandardLocation location, - AtomicReference typeSuffix, - AtomicReference moduleInfoFile, - AtomicReference srcPath) { - Filer filer = processingEnv.getFiler(); - try { - FileObject f = filer.getResource(location, "", REAL_MODULE_INFO_JAVA_NAME); - URI uri = f.toUri(); - Path filePath = toPath(uri).orElse(null); - if (filePath != null) { - Path parent = filePath.getParent(); - if (srcPath != null) { - srcPath.set(parent.toFile()); - } - if (typeSuffix != null) { - String type = inferSourceOrTest(parent); - typeSuffix.set(type); - } - if (filePath.toFile().exists()) { - if (moduleInfoFile != null) { - moduleInfoFile.set(filePath.toFile()); - } - return Optional.of(ModuleInfoDescriptor.create(filePath)); - } - } - } catch (Exception e) { - debug("unable to retrieve " + location + " from filer: " + e.getMessage()); - } - - return Optional.empty(); - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/BaseAnnotationProcessor.java b/inject/processor/src/main/java/io/helidon/inject/processor/BaseAnnotationProcessor.java deleted file mode 100644 index 36d8b1a9e78..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/BaseAnnotationProcessor.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.tools.Options; - -/** - * Abstract base for all Helidon annotation processing. - */ -abstract class BaseAnnotationProcessor extends AbstractProcessor { - private static final AtomicBoolean LOGGED_WARNING = new AtomicBoolean(); - private final System.Logger logger = System.getLogger(getClass().getName()); - - private ActiveProcessorUtils utils; - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - protected BaseAnnotationProcessor() { - } - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - public void init(ProcessingEnvironment processingEnv) { - this.utils = new ActiveProcessorUtils(this, processingEnv); - super.init(processingEnv); - - if (!Options.isOptionEnabled(Options.TAG_ACCEPT_PREVIEW) - && LOGGED_WARNING.compareAndSet(false, true)) { - processingEnv.getMessager() - .printMessage(Diagnostic.Kind.WARNING, - "Helidon Inject is preview feature, and the API and SPI may be modified in a future" - + " revision. It is considered a production feature." - + " This warning can be disabled by compiler argument -Ainject.acceptPreview=true"); - } - } - - @Override - public abstract Set getSupportedAnnotationTypes(); - - System.Logger logger() { - return logger; - } - - ActiveProcessorUtils utils() { - return Objects.requireNonNull(utils); - } - - Optional toTypeElement(TypeName typeName) { - return Optional.ofNullable(processingEnv.getElementUtils().getTypeElement(typeName.resolvedName())); - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/CreatorHandler.java b/inject/processor/src/main/java/io/helidon/inject/processor/CreatorHandler.java deleted file mode 100644 index 0b91db679fb..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/CreatorHandler.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.Objects; - -import javax.annotation.processing.ProcessingEnvironment; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.tools.AbstractFilerMessager; -import io.helidon.inject.tools.ActivatorCreatorProvider; -import io.helidon.inject.tools.ActivatorCreatorRequest; -import io.helidon.inject.tools.ActivatorCreatorResponse; -import io.helidon.inject.tools.CodeGenFiler; -import io.helidon.inject.tools.CodeGenInterceptorRequest; -import io.helidon.inject.tools.InterceptorCreatorResponse; -import io.helidon.inject.tools.Messager; -import io.helidon.inject.tools.spi.ActivatorCreator; - -/** - * Provides wrapping of the {@link ActivatorCreator}}. - */ -class CreatorHandler implements ActivatorCreator { - private final String name; - private final CodeGenFiler filer; - private final Messager messager; - - CreatorHandler(String name, - ProcessingEnvironment processingEnv, - Messager messager) { - this.name = Objects.requireNonNull(name); - this.filer = CodeGenFiler.create(AbstractFilerMessager.createAnnotationBasedFiler(processingEnv, messager)); - this.messager = Objects.requireNonNull(messager); - } - - // note: overrides ActivatorCreator - @Override - public ActivatorCreatorResponse createModuleActivators(ActivatorCreatorRequest request) { - messager.debug(name + ": createModuleActivators: " + request); - return ActivatorCreatorProvider.instance().createModuleActivators(request); - } - - // note: overrides ActivatorCreator - @Override - public InterceptorCreatorResponse codegenInterceptors(CodeGenInterceptorRequest request) { - messager.debug(name + ": codegenInterceptors(): " + request); - return ActivatorCreatorProvider.instance().codegenInterceptors(request); - } - - // note: overrides ActivatorCreator - @Override - public TypeName toActivatorImplTypeName(TypeName activatorTypeName) { - return ActivatorCreatorProvider.instance() - .toActivatorImplTypeName(activatorTypeName); - } - - CodeGenFiler filer() { - return filer; - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/CustomAnnotationProcessor.java b/inject/processor/src/main/java/io/helidon/inject/processor/CustomAnnotationProcessor.java deleted file mode 100644 index e1193194750..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/CustomAnnotationProcessor.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.common.processor.TypeFactory; -import io.helidon.common.processor.TypeInfoFactory; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.tools.AbstractFilerMessager; -import io.helidon.inject.tools.CodeGenFiler; -import io.helidon.inject.tools.CustomAnnotationTemplateRequest; -import io.helidon.inject.tools.CustomAnnotationTemplateResponse; -import io.helidon.inject.tools.CustomAnnotationTemplateResponses; -import io.helidon.inject.tools.ToolsException; -import io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator; - -import static io.helidon.inject.processor.GeneralProcessorUtils.hasValue; -import static io.helidon.inject.processor.GeneralProcessorUtils.rootStackTraceElementOf; -import static io.helidon.inject.tools.TypeTools.isStatic; -import static io.helidon.inject.tools.TypeTools.toAccess; -import static io.helidon.inject.tools.TypeTools.toFilePath; - -/** - * Processor for all {@link CustomAnnotationTemplateCreator}'s. - */ -public class CustomAnnotationProcessor extends BaseAnnotationProcessor { - private static final Map> PRODUCERS_BY_ANNOTATION = new ConcurrentHashMap<>(); - private static final Set ALL_ANNO_TYPES_HANDLED = new CopyOnWriteArraySet<>(); - private static final List PRODUCERS = initialize(); - private static final Set ALREADY_PROCESSED = new CopyOnWriteArraySet<>(); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public CustomAnnotationProcessor() { - } - - static List initialize() { - List creators = HelidonServiceLoader.create(loader()).asList(); - creators.forEach(creator -> { - try { - Set annoTypes = creator.annoTypes(); - annoTypes.forEach(annoType -> { - PRODUCERS_BY_ANNOTATION.compute(annoType, (k, v) -> { - if (v == null) { - v = new LinkedHashSet<>(); - } - v.add(creator); - return v; - }); - }); - ALL_ANNO_TYPES_HANDLED.addAll(annoTypes.stream() - .map(TypeName::fqName) - .toList()); - } catch (Throwable t) { - System.Logger logger = System.getLogger(CustomAnnotationProcessor.class.getName()); - ToolsException te = new ToolsException("Failed to initialize: " + creator, t); - logger.log(System.Logger.Level.ERROR, te.getMessage(), te); - throw te; - } - }); - return creators; - } - - @Override - public void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - logger().log(System.Logger.Level.DEBUG, CustomAnnotationTemplateCreator.class.getSimpleName() + "s: " + PRODUCERS); - } - - @Override - public boolean process(Set annotations, - RoundEnvironment roundEnv) { - try { - if (roundEnv.processingOver()) { - ALREADY_PROCESSED.clear(); - } else { - for (String annoType : getSupportedAnnotationTypes()) { - TypeName annoName = TypeName.create(annoType); - Optional annoElement = toTypeElement(annoName); - if (annoElement.isEmpty()) { - continue; - } - Set typesToProcess = roundEnv.getElementsAnnotatedWith(annoElement.get()); - doInner(annoName, typesToProcess); - } - } - - return ActiveProcessorUtils.MAYBE_ANNOTATIONS_CLAIMED_BY_THIS_PROCESSOR; - } catch (Throwable t) { - utils().error(getClass().getSimpleName() + " error during processing; " + t + " @ " - + rootStackTraceElementOf(t), t); - // we typically will not even get to this next line since the messager.error() call will trigger things to halt - throw new ToolsException("Error while processing: " + t + " @ " - + rootStackTraceElementOf(t), t); - } - } - - @Override - public Set getSupportedAnnotationTypes() { - return Set.copyOf(ALL_ANNO_TYPES_HANDLED); - } - - Set producersForType(TypeName annoTypeName) { - Set set = PRODUCERS_BY_ANNOTATION.get(annoTypeName); - return (set == null) ? Set.of() : Set.copyOf(set); - } - - void doInner(TypeName annoTypeName, - Set typesToProcess) { - if (typesToProcess.isEmpty()) { - return; - } - - Collection producers = producersForType(annoTypeName); - if (producers.isEmpty()) { - return; - } - - for (Element typeToProcess : typesToProcess) { - try { - CustomAnnotationTemplateRequest.Builder req = toRequestBuilder(annoTypeName, typeToProcess); - if (req == null) { - continue; - } - - CustomAnnotationTemplateResponse.Builder res = CustomAnnotationTemplateResponse.builder(); - - for (CustomAnnotationTemplateCreator producer : producers) { - req.genericTemplateCreator(new GenericTemplateCreatorDefault(producer.getClass(), utils())); - CustomAnnotationTemplateRequest request = req.build(); - res.request(request); - CustomAnnotationTemplateResponse producerResponse = process(producer, request); - if (producerResponse != null) { - res = CustomAnnotationTemplateResponses.aggregate(request, res.build(), producerResponse); - } - } - CustomAnnotationTemplateResponse response = res.build(); - if (req.isFilerEnabled()) { - doFiler(response); - } - } catch (Throwable t) { - throw new ToolsException("Error while processing: " + typesToProcess + t, t); - } - } - } - - void doFiler(CustomAnnotationTemplateResponse response) { - AbstractFilerMessager filer = AbstractFilerMessager.createAnnotationBasedFiler(processingEnv, utils()); - CodeGenFiler codegen = CodeGenFiler.create(filer); - response.generatedSourceCode().forEach((typeName, srcBody) -> { - if (ALREADY_PROCESSED.add(typeName)) { - codegen.codegenJavaFilerOut(typeName, srcBody); - } - }); - response.generatedResources().forEach((typedElementName, resourceBody) -> { - String fileType = typedElementName.elementName(); - if (!hasValue(fileType)) { - fileType = ".generated"; - } - codegen.codegenResourceFilerOut(toFilePath(typedElementName.typeName(), fileType), resourceBody); - }); - } - - CustomAnnotationTemplateResponse process(CustomAnnotationTemplateCreator producer, - CustomAnnotationTemplateRequest req) { - if (producer == null) { - return null; - } - - try { - CustomAnnotationTemplateResponse res = producer.create(req).orElse(null); - if (res != null && req.isFilerEnabled() && !res.generatedSourceCode().isEmpty()) { - res.generatedSourceCode().entrySet().forEach(entry -> { - TypeFactory.ensureIsFqn(entry.getKey()); - if (!hasValue(entry.getValue())) { - throw new ToolsException("Expected to have valid code for: " + req + " for " + entry); - } - }); - } - return res; - } catch (Throwable t) { - throw new ToolsException("Failed in producer: " + producer + "; " + t, t); - } - } - - CustomAnnotationTemplateRequest.Builder toRequestBuilder(TypeName annoTypeName, - Element typeToProcess) { - TypeElement enclosingClassType = toEnclosingClassTypeElement(typeToProcess); - TypeName enclosingClassTypeName = TypeFactory.createTypeName(enclosingClassType).orElse(null); - if (enclosingClassTypeName == null) { - return null; - } - - TypeInfo enclosingClassTypeInfo = utils() - .toTypeInfo(enclosingClassType, (typedElement) -> true) - .orElseThrow(); - ServiceInfoBasics siInfo = GeneralProcessorUtils.toBasicServiceInfo(enclosingClassTypeInfo); - if (siInfo == null) { - return null; - } - - Elements elements = processingEnv.getElementUtils(); - return CustomAnnotationTemplateRequest.builder() - .isFilerEnabled(true) - .annoTypeName(annoTypeName) - .serviceInfo(siInfo) - .targetElement(TypeInfoFactory.createTypedElementInfoFromElement(processingEnv, typeToProcess, elements) - .orElseThrow()) - .enclosingTypeInfo(enclosingClassTypeInfo) - // the following are duplicates that should be removed - get them from the enclosingTypeInfo instead - // see https://github.com/helidon-io/helidon/issues/6773 - .targetElementArgs(toArgs(typeToProcess)) - .targetElementAccess(toAccess(typeToProcess)) - .isElementStatic(isStatic(typeToProcess)); - } - - List toArgs(Element typeToProcess) { - if (!(typeToProcess instanceof ExecutableElement executableElement)) { - return List.of(); - } - - Elements elements = processingEnv.getElementUtils(); - List result = new ArrayList<>(); - executableElement.getParameters().forEach(v -> result.add( - TypeInfoFactory.createTypedElementInfoFromElement(processingEnv, v, elements).orElseThrow())); - return result; - } - - private static ServiceLoader loader() { - try { - // note: it is important to use this class' CL since maven will not give us the "right" one. - return ServiceLoader.load( - CustomAnnotationTemplateCreator.class, CustomAnnotationTemplateCreator.class.getClassLoader()); - } catch (ServiceConfigurationError e) { - // see issue #6261 - running inside the IDE? - // this version will use the thread ctx classloader - System.getLogger(CustomAnnotationProcessor.class.getName()).log(System.Logger.Level.WARNING, e.getMessage(), e); - return ServiceLoader.load(CustomAnnotationTemplateCreator.class); - } - } - - private static TypeElement toEnclosingClassTypeElement(Element typeToProcess) { - while (typeToProcess != null && !(typeToProcess instanceof TypeElement)) { - typeToProcess = typeToProcess.getEnclosingElement(); - } - return (typeToProcess == null) ? null : (TypeElement) typeToProcess; - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/GeneralProcessorUtils.java b/inject/processor/src/main/java/io/helidon/inject/processor/GeneralProcessorUtils.java deleted file mode 100644 index 5ef8d78afc3..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/GeneralProcessorUtils.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.net.URI; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.Weight; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.Annotations; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.RunLevel; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.tools.Options; -import io.helidon.inject.tools.TypeNames; -import io.helidon.inject.tools.TypeTools; - -/** - * Carries static methods that are agnostic to the active processing environment. - * - * @see ActiveProcessorUtils - */ -public final class GeneralProcessorUtils { - private GeneralProcessorUtils() { - } - - /** - * Determines the root throwable stack trace element from a chain of throwable causes. - * - * @param t the throwable - * @return the root throwable error stack trace element - */ - static StackTraceElement rootStackTraceElementOf(Throwable t) { - while (t.getCause() != null && t.getCause() != t) { - t = t.getCause(); - } - return t.getStackTrace()[0]; - } - - /** - * Will return non-empty File if the uri represents a local file on the fs. - * - * @param uri the uri of the artifact - * @return the file instance, or empty if not local - */ - static Optional toPath(URI uri) { - if (uri.getHost() != null) { - return Optional.empty(); - } - return Optional.of(Paths.get(uri)); - } - - /** - * Attempts to resolve the {@link RunLevel} value assigned to the provided service. - * - * @param service the service - * @return the declared run level if available - */ - static Optional toRunLevel(TypeInfo service) { - Annotation runLevelAnno = - Annotations.findFirst(RunLevel.class, service.annotations()).orElse(null); - if (runLevelAnno != null) { - return Optional.of(Integer.valueOf(runLevelAnno.value().orElseThrow())); - } - - // RunLevel is not inheritable - we will therefore not search up the hierarchy - - return Optional.empty(); - } - - /** - * Attempts to resolve the {@link Weight} value assigned to the provided service. - * - * @param service the service - * @return the declared weight if available - */ - static Optional toWeight(TypeInfo service) { - Annotation weightAnno = - Annotations.findFirst(Weight.class, service.annotations()).orElse(null); - if (weightAnno != null) { - return Optional.of(Double.valueOf(weightAnno.value().orElseThrow())); - } - - // Weight is not inheritable - we will therefore not search up the hierarchy - - return Optional.empty(); - } - - /** - * Attempts to resolve the {@code PostConstruct} method name assigned to the provided service. - * - * @param service the service - * @return the post construct method if available - */ - static Optional toPostConstructMethod(TypeInfo service) { - List postConstructs = service.elementInfo().stream() - .filter(it -> it.hasAnnotation(TypeNames.JAKARTA_POST_CONSTRUCT_TYPE)) - .map(TypedElementInfo::elementName) - .toList(); - if (postConstructs.size() == 1) { - return Optional.of(postConstructs.get(0)); - } else if (postConstructs.size() > 1) { - throw new IllegalStateException("There can be at most one " - + TypeNames.JAKARTA_POST_CONSTRUCT - + " annotated method per type: " + service.typeName()); - } - - // PostConstruct is not inheritable - we will therefore not search up the hierarchy - - return Optional.empty(); - } - - /** - * Attempts to resolve the {@code PreDestroy} method name assigned to the provided service. - * - * @param service the service - * @return the pre destroy method if available - */ - static Optional toPreDestroyMethod(TypeInfo service) { - List preDestroys = service.elementInfo().stream() - .filter(it -> it.hasAnnotation(TypeNames.JAKARTA_PRE_DESTROY_TYPE)) - .map(TypedElementInfo::elementName) - .toList(); - if (preDestroys.size() == 1) { - return Optional.of(preDestroys.get(0)); - } else if (preDestroys.size() > 1) { - throw new IllegalStateException("There can be at most one " - + TypeNames.JAKARTA_PRE_DESTROY - + " annotated method per type: " + service.typeName()); - } - - // PreDestroy is not inheritable - we will therefore not search up the hierarchy - // if (service.superTypeInfo().isPresent()) { - // return toPreDestroyMethod(service.superTypeInfo().get()); - // } - - return Optional.empty(); - } - - /** - * Attempts to resolve the scope names of the provided service. - * - * @param service the service - * @return the set of declared scope names - */ - static Set toScopeNames(TypeInfo service) { - Set scopeAnnotations = new LinkedHashSet<>(); - - service.referencedTypeNamesToAnnotations() - .forEach((typeName, listOfAnnotations) -> { - if (listOfAnnotations.stream() - .map(Annotation::typeName) - .anyMatch(TypeNames.JAKARTA_SCOPE_TYPE::equals)) { - scopeAnnotations.add(typeName); - } - }); - - if (Options.isOptionEnabled(Options.TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE)) { - boolean hasApplicationScope = service.hasAnnotation(TypeNames.JAKARTA_APPLICATION_SCOPED_TYPE); - if (hasApplicationScope) { - scopeAnnotations.add(TypeNames.JAKARTA_SINGLETON_TYPE); - scopeAnnotations.add(TypeNames.JAKARTA_APPLICATION_SCOPED_TYPE); - } - } - - return scopeAnnotations; - } - - /** - * Returns the type hierarchy of the provided service type info. - * - * @param service the service - * @return the type hierarchy - */ - static List toServiceTypeHierarchy(TypeInfo service) { - List result = new ArrayList<>(); - result.add(service.typeName()); - service.superTypeInfo().ifPresent(it -> result.addAll(toServiceTypeHierarchy(it))); - return result; - } - - /** - * Returns the qualifiers assigned to the provided service type info. - * - * @param service the service - * @return the qualifiers of the service - */ - static Set toQualifiers(TypeInfo service) { - Set result = new LinkedHashSet<>(); - - for (Annotation anno : service.annotations()) { - List metaAnnotations = service.referencedTypeNamesToAnnotations().get(anno.typeName()); - Optional qual = findFirst(TypeNames.JAKARTA_QUALIFIER, metaAnnotations); - if (qual.isPresent()) { - result.add(Qualifier.create(anno)); - } - } - - // note: should qualifiers be inheritable? Right now we assume not to support the jsr-330 spec. - // service.superTypeInfo().ifPresent(it -> result.addAll(toQualifiers(it))); - // service.interfaceTypeInfo().forEach(it -> result.addAll(toQualifiers(it))); - - return result; - } - - /** - * Returns the qualifiers assigned to the provided typed element belonging to the associated service. - * - * @param element the typed element (e.g., field, method, or constructor) - * @param service the service for which the typed element belongs - * @return the qualifiers associated with the provided element - */ - static Set toQualifiers(TypedElementInfo element, - TypeInfo service) { - Set result = new LinkedHashSet<>(); - - for (Annotation anno : element.annotations()) { - List metaAnnotations = service.referencedTypeNamesToAnnotations().get(anno.typeName()); - Optional qual = (metaAnnotations == null) - ? Optional.empty() : findFirst(TypeNames.JAKARTA_QUALIFIER, metaAnnotations); - if (qual.isPresent()) { - result.add(Qualifier.create(anno)); - } - } - - // note: should qualifiers be inheritable? Right now we assume not to support the jsr-330 spec (see note above). - - return result; - } - - /** - * Returns true if the provided type name is a {@code Provider<>} type. - * - * @param typeName the type name to check - * @return true if the provided type is a provider type. - */ - public static boolean isProviderType(TypeName typeName) { - String name = typeName.name(); - return ( - name.equals(TypeNames.JAKARTA_PROVIDER) - || name.equals(TypeNames.JAVAX_PROVIDER) - || name.equals(TypeNames.INJECTION_POINT_PROVIDER) - || TypeNames.INJECTION_SERVICE_PROVIDER.equals(name)); - } - - /** - * Simple check to see the passed String value is non-null and non-blank. - * - * @param val the value to check - * @return true if non-null and non-blank - */ - static boolean hasValue(String val) { - return (val != null && !val.isBlank()); - } - - /** - * Looks for either a jakarta or javax annotation. - * - * @param annoType the annotation type - * @param annotations the set of annotations to look in - * @return the optional annotation if there is a match - */ - static Optional findFirst(String annoType, - Collection annotations) { - if (annotations == null) { - return Optional.empty(); - } - - Optional anno = Annotations.findFirst(annoType, annotations); - if (anno.isPresent()) { - return anno; - } - - return Annotations.findFirst(TypeTools.oppositeOf(annoType), annotations); - } - - static ServiceInfoBasics toBasicServiceInfo(TypeInfo service) { - return ServiceInfo.builder() - .serviceTypeName(service.typeName()) - .update(it -> toWeight(service).ifPresent(it::declaredWeight)) - .update(it -> toRunLevel(service).ifPresent(it::declaredRunLevel)) - .scopeTypeNames(toScopeNames(service)) - .build(); - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/GenericTemplateCreatorDefault.java b/inject/processor/src/main/java/io/helidon/inject/processor/GenericTemplateCreatorDefault.java deleted file mode 100644 index 1079ce8dbdd..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/GenericTemplateCreatorDefault.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -import io.helidon.common.processor.TypeFactory; -import io.helidon.common.types.TypeName; -import io.helidon.inject.tools.CustomAnnotationTemplateRequest; -import io.helidon.inject.tools.CustomAnnotationTemplateResponse; -import io.helidon.inject.tools.GenericTemplateCreator; -import io.helidon.inject.tools.GenericTemplateCreatorRequest; -import io.helidon.inject.tools.Messager; -import io.helidon.inject.tools.TemplateHelper; -import io.helidon.inject.tools.ToolsException; - -/** - * Default implementation for {@link GenericTemplateCreator}. - */ -class GenericTemplateCreatorDefault implements GenericTemplateCreator { - private final Class generator; - private final Messager messager; - - /** - * Constructor. - * - * @param generator the class type for the generator - */ - GenericTemplateCreatorDefault(Class generator) { - this(generator, new MessagerToLogAdapter(System.getLogger(GenericTemplateCreatorDefault.class.getName()))); - } - - /** - * Constructor. - * - * @param generator the class type for the generator - * @param messager the messager and error handler - */ - GenericTemplateCreatorDefault(Class generator, - Messager messager) { - this.generator = Objects.requireNonNull(generator); - this.messager = messager; - } - - @Override - public Optional create(GenericTemplateCreatorRequest req) { - Objects.requireNonNull(req); - if (!TypeFactory.isFqn(req.generatedTypeName())) { - messager.debug("skipping custom template production for: " + req.generatedTypeName() + " = " + req); - return Optional.empty(); - } - - TemplateHelper templateHelper = TemplateHelper.create(); - Map substitutions = gatherSubstitutions(req, templateHelper); - String javaBody = templateHelper.applySubstitutions(req.template(), substitutions, true); - return Optional.of(CustomAnnotationTemplateResponse.builder() - .request(req.customAnnotationTemplateRequest()) - .putGeneratedSourceCode(req.generatedTypeName(), javaBody) - .build()); - } - - /** - * Returns the template that will rely on a resource lookup of resources/inject/{templateProfile}/{templateName}. - * Note: This will only work for non-module based usages, and therefore is not recommended for general use. - * - * @param templateProfile the template profile to apply (must be exported by the spi provider module; "default" is reserved - * for internal use) - * @param templateName the template name - * @return the generic template resource - */ - CharSequence supplyFromResources(String templateProfile, - String templateName) { - TemplateHelper templateHelper = TemplateHelper.create(); - String template = templateHelper.loadTemplate(templateProfile, templateName); - if (template == null) { - ToolsException te = new ToolsException("Unable to find template " + templateProfile + "/" + templateName); - messager.error(te.getMessage(), te); - throw te; - } - - return template; - } - - Map gatherSubstitutions(GenericTemplateCreatorRequest genericRequest, - TemplateHelper templateHelper) { - CustomAnnotationTemplateRequest req = genericRequest.customAnnotationTemplateRequest(); - TypeName generatedTypeName = genericRequest.generatedTypeName(); - Map substitutions = new HashMap<>(); - - TypeName generatorType = TypeName.create(generator); - TypeName serviceType = req.serviceInfo().serviceTypeName(); - substitutions.put("generatedSticker", templateHelper.generatedStickerFor(generatorType, serviceType, generatedTypeName)); - substitutions.put("annoTypeName", req.annoTypeName()); - substitutions.put("generatedTypeName", generatedTypeName); - substitutions.put("packageName", generatedTypeName.packageName()); - substitutions.put("className", generatedTypeName.className()); - substitutions.put("enclosingClassTypeName", req.enclosingTypeInfo().typeName()); - substitutions.put("enclosingAnnotations", req.enclosingTypeInfo().annotations()); - substitutions.put("basicServiceInfo", req.serviceInfo()); - substitutions.put("weight", req.serviceInfo().realizedWeight()); - substitutions.put("runLevel", req.serviceInfo().realizedRunLevel()); - substitutions.put("elementKind", req.targetElement().elementTypeKind()); - substitutions.put("elementName", req.targetElement().elementName()); - substitutions.put("elementAnnotations", req.targetElement().annotations()); - substitutions.put("elementEnclosingTypeName", req.targetElement().typeName()); - substitutions.putAll(genericRequest.overrideProperties()); - return substitutions; - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/InjectionAnnotationProcessor.java b/inject/processor/src/main/java/io/helidon/inject/processor/InjectionAnnotationProcessor.java deleted file mode 100644 index 19b396774bc..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/InjectionAnnotationProcessor.java +++ /dev/null @@ -1,910 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.common.processor.TypeFactory; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.Annotations; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypeValues; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.Contract; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.ExternalContracts; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.processor.spi.InjectionAnnotationProcessorObserver; -import io.helidon.inject.runtime.Dependencies; -import io.helidon.inject.tools.ActivatorCreatorCodeGen; -import io.helidon.inject.tools.ActivatorCreatorConfigOptions; -import io.helidon.inject.tools.ActivatorCreatorDefault; -import io.helidon.inject.tools.ActivatorCreatorRequest; -import io.helidon.inject.tools.ActivatorCreatorResponse; -import io.helidon.inject.tools.InterceptionPlan; -import io.helidon.inject.tools.InterceptorCreatorProvider; -import io.helidon.inject.tools.Options; -import io.helidon.inject.tools.ServicesToProcess; -import io.helidon.inject.tools.ToolsException; -import io.helidon.inject.tools.TypeNames; -import io.helidon.inject.tools.spi.ActivatorCreator; -import io.helidon.inject.tools.spi.InterceptorCreator; - -import static io.helidon.common.processor.TypeInfoFactory.createTypedElementInfoFromElement; -import static io.helidon.common.processor.TypeInfoFactory.isBuiltInJavaType; -import static io.helidon.inject.processor.GeneralProcessorUtils.isProviderType; -import static io.helidon.inject.processor.GeneralProcessorUtils.rootStackTraceElementOf; -import static io.helidon.inject.processor.GeneralProcessorUtils.toBasicServiceInfo; -import static io.helidon.inject.processor.GeneralProcessorUtils.toPostConstructMethod; -import static io.helidon.inject.processor.GeneralProcessorUtils.toPreDestroyMethod; -import static io.helidon.inject.processor.GeneralProcessorUtils.toQualifiers; -import static io.helidon.inject.processor.GeneralProcessorUtils.toRunLevel; -import static io.helidon.inject.processor.GeneralProcessorUtils.toScopeNames; -import static io.helidon.inject.processor.GeneralProcessorUtils.toServiceTypeHierarchy; -import static io.helidon.inject.processor.GeneralProcessorUtils.toWeight; -import static io.helidon.inject.tools.CodeGenFiler.scratchClassOutputPath; -import static io.helidon.inject.tools.CodeGenFiler.targetClassOutputPath; -import static io.helidon.inject.tools.TypeTools.toAccess; -import static java.util.Objects.requireNonNull; - -/** - * An annotation processor that will find everything needing to be processed related to core code generation. - */ -public class InjectionAnnotationProcessor extends BaseAnnotationProcessor { - private static final Set SUPPORTED_SERVICE_CLASS_TARGET_ANNOTATIONS = Set.of( - TypeNames.JAKARTA_SINGLETON, - TypeNames.JAVAX_SINGLETON, - TypeNames.JAKARTA_APPLICATION_SCOPED, - TypeNames.JAVAX_APPLICATION_SCOPED, - TypeNames.EXTERNAL_CONTRACTS, - TypeNames.INTERCEPTED); - private static final Set SUPPORTED_CONTRACT_CLASS_TARGET_ANNOTATIONS = Set.of( - TypeNames.CONTRACT); - private static final Set SUPPORTED_ELEMENT_TARGET_ANNOTATIONS = Set.of( - TypeNames.JAKARTA_INJECT, - TypeNames.JAVAX_INJECT, - TypeNames.JAKARTA_PRE_DESTROY, - TypeNames.JAKARTA_POST_CONSTRUCT, - TypeNames.JAVAX_PRE_DESTROY, - TypeNames.JAVAX_POST_CONSTRUCT); - private static final Set SERVICE_DEFINING_ANNOTATIONS = Set.of( - TypeName.create(TypeNames.JAKARTA_SINGLETON), - TypeName.create(TypeNames.JAKARTA_APPLICATION_SCOPED) - ); - private static boolean disableBaseProcessing; - private final Set alreadyProcessed = new LinkedHashSet<>(); - private final Set allElementsOfInterestInThisModule = new LinkedHashSet<>(); - private final Map typeInfoToCreateActivatorsForInThisModule = new LinkedHashMap<>(); - private ProcessingTracker tracker; - private CreatorHandler creator; - private boolean autoAddInterfaces; - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public InjectionAnnotationProcessor() { - } - - /** - * Any overriding APT processor can optionally pass {@code false} in order to prevent duplicate base processing. - * - * @param disableBaseProcessing set to true to disable base processing - */ - protected InjectionAnnotationProcessor(boolean disableBaseProcessing) { - if (disableBaseProcessing) { - InjectionAnnotationProcessor.disableBaseProcessing = true; - } - } - - @Override - public Set getSupportedAnnotationTypes() { - return Stream.of(supportedServiceClassTargetAnnotations(), - supportedContractClassTargetAnnotations(), - supportedElementTargetAnnotations()) - .flatMap(Set::stream) - .collect(Collectors.toSet()); - } - - @Override - public void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - this.autoAddInterfaces = Options.isOptionEnabled(Options.TAG_AUTO_ADD_NON_CONTRACT_INTERFACES); - this.creator = new CreatorHandler(getClass().getSimpleName(), processingEnv, utils()); - this.tracker = ProcessingTracker.initializeFrom(trackerStatePath(), processingEnv); - } - - @Override - public final boolean process(Set annotations, - RoundEnvironment roundEnv) { - Thread thread = Thread.currentThread(); - ClassLoader previousClassloader = thread.getContextClassLoader(); - thread.setContextClassLoader(InjectionAnnotationProcessor.class.getClassLoader()); - - // we want everything to execute in the classloader of this type, so service loaders - // use the classpath of the annotation processor, and not some "random" classloader, such as a maven one - try { - return doProcess(annotations, roundEnv); - } finally { - thread.setContextClassLoader(previousClassloader); - } - } - - private boolean doProcess(Set ignoredAnnotations, - RoundEnvironment roundEnv) { - utils().roundEnv(roundEnv); - - if (disableBaseProcessing && getClass() == InjectionAnnotationProcessor.class) { - return false; - } - - ServicesToProcess.onBeginProcessing(utils(), getSupportedAnnotationTypes(), roundEnv); - - try { - // build the model - Set elementsOfInterestInThisRound = gatherElementsOfInterestInThisModule(); - validate(elementsOfInterestInThisRound); - allElementsOfInterestInThisModule.addAll(elementsOfInterestInThisRound); - - // cumulatively collect the types to process in the module - gatherTypeInfosToProcessInThisModule(typeInfoToCreateActivatorsForInThisModule, - allElementsOfInterestInThisModule); - - // optionally intercept and validate the model - Set filtered = new LinkedHashSet<>(typeInfoToCreateActivatorsForInThisModule.values()); - filtered = interceptAndValidate(filtered); - - // code generate the model - ServicesToProcess services = toServicesToProcess(filtered, allElementsOfInterestInThisModule); - doFiler(services); - - notifyObservers(); - - if (roundEnv.processingOver()) { - alreadyProcessed.clear(); - } - - return ActiveProcessorUtils.MAYBE_ANNOTATIONS_CLAIMED_BY_THIS_PROCESSOR; - } catch (Throwable t) { - ToolsException exc = new ToolsException("Error while processing: " + t - + " @ " + rootStackTraceElementOf(t) - + " in " + getClass().getSimpleName(), t); - utils().error(exc.getMessage(), t); - // we typically will not even get to this next line since the messager.error() call above will trigger things to halt - throw exc; - } finally { - ServicesToProcess.onEndProcessing(utils(), getSupportedAnnotationTypes(), roundEnv); - if (roundEnv.processingOver()) { - allElementsOfInterestInThisModule.clear(); - typeInfoToCreateActivatorsForInThisModule.clear(); - } - utils().roundEnv(null); - } - } - - /** - * Returns the activator creator in use. - * - * @return the activator creator in use - */ - protected ActivatorCreator activatorCreator() { - return creator; - } - - /** - * The annotation types we handle that will trigger activator creation. - * - * @return annotation types we handle on services - */ - protected Set supportedServiceClassTargetAnnotations() { - return SUPPORTED_SERVICE_CLASS_TARGET_ANNOTATIONS; - } - - /** - * The annotation types we handle that will be advertised as contracts. - * - * @return annotation types we handle on contracts - */ - protected Set supportedContractClassTargetAnnotations() { - return SUPPORTED_CONTRACT_CLASS_TARGET_ANNOTATIONS; - } - - /** - * The annotation types we expect to see on method and field type elements. - * - * @return annotation types we handle on elements - */ - protected Set supportedElementTargetAnnotations() { - return SUPPORTED_ELEMENT_TARGET_ANNOTATIONS; - } - - /** - * Code generate these {@link Activator}'s ad {@link ModuleComponent}'s. - * - * @param services the services to code generate - * @throws ToolsException if there is problem code generating sources or resources - */ - protected void doFiler(ServicesToProcess services) { - ActivatorCreatorCodeGen codeGen = ActivatorCreatorDefault.createActivatorCreatorCodeGen(services).orElse(null); - if (codeGen == null) { - return; - } - - boolean processingOver = utils().roundEnv().processingOver(); - ActivatorCreatorConfigOptions configOptions = ActivatorCreatorConfigOptions.builder() - .applicationPreCreated(Options.isOptionEnabled(Options.TAG_APPLICATION_PRE_CREATE)) - .moduleCreated(processingOver) - .build(); - ActivatorCreatorRequest req = ActivatorCreatorDefault - .createActivatorCreatorRequest(services, codeGen, configOptions, creator.filer(), false); - Set allActivatorTypeNames = tracker.remainingTypeNames().stream() - .map(TypeName::create) - .collect(Collectors.toSet()); - if (!allActivatorTypeNames.isEmpty()) { - req = ActivatorCreatorRequest.builder(req) - .codeGen(ActivatorCreatorCodeGen.builder(req.codeGen()) - .allModuleActivatorTypeNames(allActivatorTypeNames) - .build()) - .build(); - } - ActivatorCreatorResponse res = creator.createModuleActivators(req); - if (res.success()) { - res.activatorTypeNamesPutInComponentModule() - .forEach(it -> tracker.processing(it.name())); - if (processingOver) { - try { - tracker.close(); - } catch (IOException e) { - throw new ToolsException(e.getMessage(), e); - } - } - } else { - ToolsException exc = new ToolsException("Error during codegen", res.error().orElse(null)); - utils().error(exc.getMessage(), exc); - // should not get here since the error above should halt further processing - throw exc; - } - } - - /** - * These are all of the elements (methods, constructors, methods) that are "interesting" (i.e., has {@code @Inject}, etc.). - * - * @param elementsOfInterest the elements that are eligible for some form of Injection processing - */ - protected void validate(Collection elementsOfInterest) { - validatePerClass( - elementsOfInterest, - "There can be max of one injectable constructor per class", - 1, - (it) -> it.elementTypeKind().equals(TypeValues.KIND_CONSTRUCTOR) - && it.hasAnnotation(TypeNames.JAKARTA_INJECT_TYPE)); - validatePerClass( - elementsOfInterest, - "There can be max of one PostConstruct method per class", - 1, - (it) -> it.elementTypeKind().equals(TypeValues.KIND_METHOD) - && it.hasAnnotation(TypeNames.JAKARTA_POST_CONSTRUCT_TYPE)); - validatePerClass( - elementsOfInterest, - "There can be max of one PreDestroy method per class", - 1, - (it) -> it.elementTypeKind().equals(TypeValues.KIND_METHOD) - && it.hasAnnotation(TypeNames.JAKARTA_PRE_DESTROY_TYPE)); - validatePerClass( - elementsOfInterest, - "Injection does not currently support static or private elements", - 0, - (it) -> it.modifiers().contains(TypeValues.MODIFIER_PRIVATE) - || it.modifiers().contains(TypeValues.MODIFIER_STATIC)); - } - - /** - * Provides a means for anyone to validate and intercept the collection of types to process. - * - * @param typesToCreateActivatorsFor the map of types to process (where key is the proposed generated name) - * @return the (possibly revised) set of types to process - */ - protected Set interceptAndValidate(Collection typesToCreateActivatorsFor) { - return new LinkedHashSet<>(Objects.requireNonNull(typesToCreateActivatorsFor)); - } - - /** - * Called to process a single service that will eventually be code generated. The default implementation will take the - * provided service {@link TypeInfo} and translate that into the {@link ServicesToProcess} instance. Eventually, the - * {@link ServicesToProcess} instance will be fed as request inputs to one or more of the creators (e.g., - * {@link ActivatorCreator}, {@link InterceptorCreator}, etc.). - * - * @param services the services to process builder - * @param service the service type info to process right now - * @param serviceTypeNamesToCodeGenerate the entire set of types that are planned to be code-generated - * @param allElementsOfInterest all of the elements of interest that injection services "knows" about - */ - protected void process(ServicesToProcess services, - TypeInfo service, - Set serviceTypeNamesToCodeGenerate, - Collection allElementsOfInterest) { - utils().debug("Code generating" + Activator.class.getSimpleName() + " for: " + service.typeName()); - processBasics(services, service, serviceTypeNamesToCodeGenerate, allElementsOfInterest); - processInterceptors(services, service, serviceTypeNamesToCodeGenerate, allElementsOfInterest); - processExtensions(services, service, serviceTypeNamesToCodeGenerate, allElementsOfInterest); - } - - /** - * Processes the basic Injection service type - its contracts, run level, weight, dependencies, etc. - * - * @param services the services to process builder - * @param service the service type info to process right now - * @param serviceTypeNamesToCodeGenerate the entire set of types that are planned to be code-generated - * @param allElementsOfInterest all of the elements of interest that injection "knows" about - */ - @SuppressWarnings("unused") - protected void processBasics(ServicesToProcess services, - TypeInfo service, - Set serviceTypeNamesToCodeGenerate, - Collection allElementsOfInterest) { - TypeName serviceTypeName = service.typeName(); - TypeInfo superTypeInfo = service.superTypeInfo().orElse(null); - if (superTypeInfo != null) { - Optional serviceProvider = findServiceProviderInHierarchy(superTypeInfo, new HashSet<>()); - if (serviceProvider.isPresent()) { - // if supertype is ServiceProvider itself, we can just extend directly - services.addParentServiceType(serviceTypeName, serviceProvider.get()); - } else { - Optional activatedType = findActivatedInHierarchy(superTypeInfo, new HashSet<>()); - if (activatedType.isPresent()) { - TypeName typeName = activatedType.get(); - // in case one the super types is activated, extend that activator - services.addParentServiceType(serviceTypeName, TypeName.builder(typeName.genericTypeName()) - .className(typeName.classNameWithEnclosingNames().replace('.', '$') - + ActivatorCreatorDefault.INNER_ACTIVATOR_CLASS_NAME) - .enclosingNames(List.of()) // activators are always flat - .build()); - } else { - // otherwise extends AbstractServiceProvider with the correct type - services.addParentServiceType(serviceTypeName, TypeName.builder(TypeNames.ABSTRACT_SERVICE_PROVIDER_TYPE) - .addTypeArgument(serviceTypeName) - .build()); - } - } - } - Set modifierNames = toModifierNames(service.modifiers()); - - toRunLevel(service).ifPresent(it -> services.addDeclaredRunLevel(serviceTypeName, it)); - toWeight(service).ifPresent(it -> services.addDeclaredWeight(serviceTypeName, it)); - toScopeNames(service).forEach(it -> services.addScopeTypeName(serviceTypeName, it)); - toPostConstructMethod(service).ifPresent(it -> services.addPostConstructMethod(serviceTypeName, it)); - toPreDestroyMethod(service).ifPresent(it -> services.addPreDestroyMethod(serviceTypeName, it)); - toInjectionDependencies(service, allElementsOfInterest).ifPresent(services::addDependencies); - services.addAccessLevel(serviceTypeName, - toAccess(modifierNames)); - services.addIsAbstract(serviceTypeName, - modifierNames.contains(TypeValues.MODIFIER_ABSTRACT)); - services.addServiceTypeHierarchy(serviceTypeName, - toServiceTypeHierarchy(service)); - services.addQualifiers(serviceTypeName, - toQualifiers(service)); - gatherContractsIntoServicesToProcess(services, service); - } - - /** - * The set of annotations that define the service. - * - * @return the set of annotations that define the service - */ - protected Set serviceDefiningAnnotations() { - return SERVICE_DEFINING_ANNOTATIONS; - } - - /** - * Process any extensions (e.g., config-driven) requiring extra processing or any modifications to {@link ServicesToProcess}. - * - * @param services the services to process builder - * @param service the service type info to process right now - * @param serviceTypeNamesToCodeGenerate the entire set of types that are planned to be code-generated - * @param allElementsOfInterest all of the elements of interest that injection "knows" about - */ - @SuppressWarnings("unused") - protected void processExtensions(ServicesToProcess services, - TypeInfo service, - Set serviceTypeNamesToCodeGenerate, - Collection allElementsOfInterest) { - // NOP; expected that derived classes will implement this - } - - /** - * Processes all of the injection points for the provided typed element, accumulating the result in the provided builder - * continuation instance. - * - * @param builder the builder continuation instance - * @param typedElement the typed element to convert - * @param service the type info of the backing service - */ - private static void gatherInjectionPoints(Dependencies.BuilderContinuation builder, - TypedElementInfo typedElement, - TypeInfo service, - Set modifierNames) { - String elemName = typedElement.elementName(); - AccessModifier access = toAccess(modifierNames); - ElementKind elemKind = ElementKind.valueOf(typedElement.elementTypeKind()); - boolean isField = (elemKind == ElementKind.FIELD); - if (isField) { - TypeName typeName = typedElement.typeName(); - boolean isOptional = typeName.isOptional(); - typeName = (isOptional) ? typeName.typeArguments().get(0) : typeName; - boolean isList = typeName.isList(); - typeName = (isList) ? typeName.typeArguments().get(0) : typeName; - boolean isProviderType = isProviderType(typeName); - typeName = (isProviderType) ? typeName.typeArguments().get(0) : typeName; - Set qualifiers = toQualifiers(typedElement, service); - - builder.add(service.typeName(), - elemName, - typeName, - elemKind, - 0, - access) - .ipName(elemName) - .ipType(typedElement.typeName()) - .qualifiers(qualifiers) - .listWrapped(isList) - .providerWrapped(isProviderType) - .optionalWrapped(isOptional); - } else { - int elemArgs = typedElement.parameterArguments().size(); - AtomicInteger elemOffset = new AtomicInteger(); - typedElement.parameterArguments().forEach(it -> { - TypeName typeName = it.typeName(); - boolean isOptional = typeName.isOptional(); - typeName = (isOptional) ? typeName.typeArguments().get(0) : typeName; - boolean isList = typeName.isList(); - typeName = (isList) ? typeName.typeArguments().get(0) : typeName; - boolean isProviderType = isProviderType(typeName); - typeName = (isProviderType) ? typeName.typeArguments().get(0) : typeName; - - int pos = elemOffset.incrementAndGet(); - Set qualifiers = toQualifiers(it, service); - - builder.add(service.typeName(), - elemName, - typeName, - elemKind, - elemArgs, - access) - .ipName(it.elementName()) - .ipType(it.typeName()) - .qualifiers(qualifiers) - .elemOffset(pos) - .listWrapped(isList) - .providerWrapped(isProviderType) - .optionalWrapped(isOptional); - }); - } - } - - // will be resolved in https://github.com/helidon-io/helidon/issues/6764 - private static Set toModifierNames(Set names) { - return names.stream().map(String::toLowerCase).collect(Collectors.toSet()); - } - - private static ServiceLoader observerLoader() { - try { - // note: it is important to use this class' CL since maven will not give us the "right" one. - return ServiceLoader.load( - InjectionAnnotationProcessorObserver.class, InjectionAnnotationProcessorObserver.class.getClassLoader()); - } catch (ServiceConfigurationError e) { - // see issue #6261 - running inside the IDE? - // this version will use the thread ctx classloader - System.getLogger(InjectionAnnotationProcessorObserver.class.getName()) - .log(System.Logger.Level.WARNING, e.getMessage(), e); - return ServiceLoader.load(InjectionAnnotationProcessorObserver.class); - } - } - - private Optional findActivatedInHierarchy(TypeInfo superTypeInfo, Set processed) { - if (!processed.add(superTypeInfo.typeName())) { - return Optional.empty(); - } - // any type that has - // - @Singleton on type (or any other "service defining annotation"), or has @Scope meta annotation - // - @Inject on any field or constructor - // same code in ExternalModuleCreatorDefault for ClassInfo - - Set serviceDefining = serviceDefiningAnnotations(); - for (Annotation annotation : superTypeInfo.annotations()) { - // bean defining - if (serviceDefining.contains(annotation.typeName())) { - return Optional.of(superTypeInfo.typeName()); - } - } - Set kindsOfInterest = Set.of(TypeValues.KIND_CONSTRUCTOR, TypeValues.KIND_FIELD, TypeValues.KIND_METHOD); - if (Stream.concat(superTypeInfo.elementInfo().stream(), superTypeInfo.otherElementInfo().stream()) - .filter(it -> kindsOfInterest.contains(it.elementTypeKind())) - .anyMatch(it -> it.hasAnnotation(TypeNames.JAKARTA_INJECT_TYPE) - || it.hasAnnotation(TypeNames.JAVAX_INJECT_TYPE))) { - return Optional.of(superTypeInfo.typeName()); - } - return superTypeInfo.superTypeInfo() - .flatMap(it -> findActivatedInHierarchy(it, processed)); - } - - private Optional findServiceProviderInHierarchy(TypeInfo superTypeInfo, Set processed) { - // any type that implements ServiceProvider (or its child) is eligible - if (!processed.add(superTypeInfo.typeName())) { - return Optional.empty(); - } - - for (TypeInfo typeInfo : superTypeInfo.interfaceTypeInfo()) { - Optional maybe = findServiceProviderInHierarchy(superTypeInfo, typeInfo, processed); - if (maybe.isPresent()) { - return maybe; - } - } - return superTypeInfo.superTypeInfo() - .flatMap(it -> findServiceProviderInHierarchy(it, processed)); - } - - private Optional findServiceProviderInHierarchy(TypeInfo classInfo, - TypeInfo interfaceInfo, - Set processed) { - if (!processed.add(interfaceInfo.typeName())) { - // already processed - return Optional.empty(); - } - if (TypeNames.SERVICE_PROVIDER_TYPE.equals(interfaceInfo.typeName())) { - // yes! - return Optional.of(classInfo.typeName()); - } - - // navigate interface hierarchy - for (TypeInfo typeInfo : interfaceInfo.interfaceTypeInfo()) { - Optional maybe = findServiceProviderInHierarchy(classInfo, typeInfo, processed); - if (maybe.isPresent()) { - return maybe; - } - } - - return Optional.empty(); - } - - private void validatePerClass(Collection elementsOfInterest, - String msg, - int maxAllowed, - Predicate matcher) { - Map> allTypeNamesToMatchingElements = new LinkedHashMap<>(); - elementsOfInterest.stream() - .filter(matcher) - .forEach(it -> allTypeNamesToMatchingElements - .computeIfAbsent(it.enclosingType().orElseThrow(), (n) -> new ArrayList<>()).add(it)); - allTypeNamesToMatchingElements.values().stream() - .filter(list -> list.size() > maxAllowed) - .forEach(it -> utils().error(msg + " for " + it.get(0).enclosingType(), null)); - } - - /** - * Process any interception plans. - * - * @param services the services to process builder - * @param service the service type info to process right now - * @param serviceTypeNamesToCodeGenerate the entire set of types that are planned to be code-generated - * @param allElementsOfInterest all of the elements of interest that injectio "knows" about - */ - @SuppressWarnings("unused") - private void processInterceptors(ServicesToProcess services, - TypeInfo service, - Set serviceTypeNamesToCodeGenerate, - Collection allElementsOfInterest) { - TypeName serviceTypeName = service.typeName(); - InterceptorCreator interceptorCreator = InterceptorCreatorProvider.instance(); - ServiceInfoBasics interceptedServiceInfo = toBasicServiceInfo(service); - InterceptorCreator.InterceptorProcessor processor = interceptorCreator.createInterceptorProcessor( - interceptedServiceInfo, - interceptorCreator, - processingEnv); - Set annotationTypeTriggers = processor.allAnnotationTypeTriggers(); - if (annotationTypeTriggers.isEmpty()) { - services.addInterceptorPlanFor(serviceTypeName, Optional.empty()); - return; - } - - Optional plan = processor.createInterceptorPlan(annotationTypeTriggers); - if (plan.isEmpty()) { - utils().log("unable to produce an interception plan for: " + serviceTypeName); - } - services.addInterceptorPlanFor(serviceTypeName, plan); - } - - private ServicesToProcess toServicesToProcess(Set typesToCodeGenerate, - Collection allElementsOfInterest) { - ServicesToProcess services = ServicesToProcess.create(); - utils().relayModuleInfoToServicesToProcess(services); - - Set typesNamesToCodeGenerate = typesToCodeGenerate.stream().map(TypeInfo::typeName).collect(Collectors.toSet()); - typesToCodeGenerate.forEach(service -> { - try { - process(services, service, typesNamesToCodeGenerate, allElementsOfInterest); - } catch (Throwable t) { - throw new ToolsException("Error while processing: " + service.typeName(), t); - } - }); - typesNamesToCodeGenerate.removeAll(alreadyProcessed); - services.generatedServiceTypeNames(typesNamesToCodeGenerate); - alreadyProcessed.addAll(typesNamesToCodeGenerate); - - return services; - } - - private void gatherContractsIntoServicesToProcess(ServicesToProcess services, - TypeInfo service) { - Set contracts = new LinkedHashSet<>(); - Set externalContracts = new LinkedHashSet<>(); - Set providerForSet = new LinkedHashSet<>(); - Set externalModuleNames = new LinkedHashSet<>(); - - gatherContracts(contracts, - externalContracts, - providerForSet, - externalModuleNames, - service, - false); - - TypeName serviceTypeName = service.typeName(); - contracts.forEach(it -> services.addTypeForContract(serviceTypeName, it, false)); - externalContracts.forEach(it -> services.addTypeForContract(serviceTypeName, it, true)); - services.addProviderFor(serviceTypeName, providerForSet); - services.addExternalRequiredModules(serviceTypeName, externalModuleNames); - - utils().debug(serviceTypeName - + ": contracts=" + contracts - + ", providers=" + providerForSet - + ", externalContracts=" + externalContracts - + ", externalModuleNames=" + externalModuleNames); - } - - private void gatherContracts(Set contracts, - Set externalContracts, - Set providerForSet, - Set externalModuleNamesRequired, - TypeInfo typeInfo, - boolean isThisTypeEligibleToBeAContract) { - TypeName fqTypeName = typeInfo.typeName(); - TypeName fqProviderTypeName = null; - if (isProviderType(fqTypeName)) { - fqProviderTypeName = fqTypeName.genericTypeName(); - fqTypeName = requireNonNull(fqTypeName.typeArguments().get(0), fqTypeName.toString()); - } - TypeName genericTypeName = fqTypeName.genericTypeName(); - - if (isThisTypeEligibleToBeAContract && !genericTypeName.wildcard()) { - if (fqProviderTypeName != null) { - if (!fqTypeName.generic()) { - providerForSet.add(genericTypeName); - extractModuleAndContract(contracts, - externalContracts, - externalModuleNamesRequired, - typeInfo, - genericTypeName); - } - - // if we are dealing with a Provider<> then we should add those too as module dependencies - TypeName genericProviderTypeName = fqProviderTypeName.genericTypeName(); - externalContracts.add(genericProviderTypeName); - filterModuleName(typeInfo.moduleNameOf(genericProviderTypeName)).ifPresent(externalModuleNamesRequired::add); - if (genericProviderTypeName.name().equals(TypeNames.INJECTION_POINT_PROVIDER)) { - TypeName jakartaProviderTypeName = TypeName.create(TypeNames.JAKARTA_PROVIDER); - externalContracts.add(jakartaProviderTypeName); - filterModuleName(typeInfo.moduleNameOf(jakartaProviderTypeName)).ifPresent(externalModuleNamesRequired::add); - } - } else { - boolean isTypeAnInterface = typeInfo.typeKind().equals(TypeValues.KIND_INTERFACE); - boolean isTypeAContract = autoAddInterfaces - || !isTypeAnInterface - || Annotations.findFirst(Contract.class, typeInfo.annotations()).isPresent(); - if (isTypeAContract) { - extractModuleAndContract(contracts, - externalContracts, - externalModuleNamesRequired, - typeInfo, - genericTypeName); - } - } - } - - Annotation externalContractAnno = Annotations - .findFirst(ExternalContracts.class, typeInfo.annotations()) - .orElse(null); - if (externalContractAnno != null) { - List externalContractNames = externalContractAnno.stringValues().orElseGet(List::of); - for (String externalContractName : externalContractNames) { - TypeName externalContractTypeName = TypeName.create(externalContractName); - externalContracts.add(externalContractTypeName); - filterModuleName(typeInfo.moduleNameOf(externalContractTypeName)).ifPresent(externalModuleNamesRequired::add); - } - - List moduleNames = externalContractAnno.stringValues("moduleNames").orElseGet(List::of); - for (String externalModuleName : moduleNames) { - if (!externalModuleName.isBlank()) { - externalModuleNamesRequired.add(externalModuleName); - } - } - } - - // process parent hierarchy - typeInfo.superTypeInfo().ifPresent(it -> gatherContracts(contracts, - externalContracts, - providerForSet, - externalModuleNamesRequired, - it, - true)); - typeInfo.interfaceTypeInfo().forEach(it -> gatherContracts(contracts, - externalContracts, - providerForSet, - externalModuleNamesRequired, - it, - true)); - } - - private void extractModuleAndContract(Set contracts, - Set externalContracts, - Set externalModuleNamesRequired, - TypeInfo typeInfo, - TypeName genericTypeName) { - Optional moduleName = filterModuleName(typeInfo.moduleNameOf(genericTypeName)); - moduleName.ifPresent(externalModuleNamesRequired::add); - if (moduleName.isPresent() || isBuiltInJavaType(genericTypeName)) { - externalContracts.add(genericTypeName); - } else { - contracts.add(genericTypeName); - } - } - - private Optional filterModuleName(Optional moduleName) { - String name = moduleName.orElse(null); - if (name != null && (name.startsWith("java.") || name.startsWith("jdk"))) { - return Optional.empty(); - } - return moduleName; - } - - private Optional toInjectionDependencies(TypeInfo service, - Collection allElementsOfInterest) { - Dependencies.BuilderContinuation builder = Dependencies.builder(service.typeName()); - gatherInjectionPoints(builder, service, allElementsOfInterest); - DependenciesInfo deps = builder.build(); - return deps.serviceInfoDependencies().isEmpty() ? Optional.empty() : Optional.of(deps); - } - - private void gatherInjectionPoints(Dependencies.BuilderContinuation builder, - TypeInfo service, - Collection allElementsOfInterest) { - List injectableElementsForThisService = allElementsOfInterest.stream() - .filter(it -> it.hasAnnotation(TypeNames.JAKARTA_INJECT_TYPE)) - .filter(it -> service.typeName().equals(it.enclosingType().orElseThrow())) - .toList(); - injectableElementsForThisService - .forEach(elem -> gatherInjectionPoints(builder, elem, service, toModifierNames(elem.modifiers()))); - - // // We expect activators at every level for abstract bases - we will therefore NOT recursive up the hierarchy - // service.superTypeInfo().ifPresent(it -> gatherInjectionPoints(builder, it, allElementsOfInterest, false)); - } - - private Set gatherElementsOfInterestInThisModule() { - Set result = new LinkedHashSet<>(); - - Elements elementUtils = processingEnv.getElementUtils(); - for (String annoType : supportedElementTargetAnnotations()) { - // annotation may not be on the classpath, in such a case just ignore it - TypeElement annoTypeElement = elementUtils.getTypeElement(annoType); - if (annoTypeElement != null) { - Set typesToProcess = utils().roundEnv().getElementsAnnotatedWith(annoTypeElement); - typesToProcess.forEach(it -> result.add(createTypedElementInfoFromElement(processingEnv, it, elementUtils) - .orElseThrow())); - } - } - - return result; - } - - private void gatherTypeInfosToProcessInThisModule(Map result, - Collection elementsOfInterest) { - // this section gathers based upon the class-level annotations in order to discover what to process - for (String annoType : supportedServiceClassTargetAnnotations()) { - // annotation may not be on the classpath, in such a case just ignore it - Elements elements = processingEnv.getElementUtils(); - TypeElement annoTypeElement = elements.getTypeElement(annoType); - if (annoTypeElement != null) { - Set typesToProcess = utils().roundEnv().getElementsAnnotatedWith(annoTypeElement); - typesToProcess.forEach(it -> { - TypeName typeName = TypeFactory.createTypeName(it).orElseThrow().genericTypeName(); - if (!result.containsKey(typeName)) { - // first time processing this type name - TypeElement typeElement = (TypeElement) it; - Optional typeInfo = - utils().toTypeInfo(typeElement, elementsOfInterest::contains); - typeInfo.ifPresent(it2 -> result.put(typeName, it2)); - } - }); - } - } - - // this section gathers based upon the element-level annotations in order to discover what to process - Set enclosingElementsOfInterest = elementsOfInterest.stream() - .map(TypedElementInfo::enclosingType) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet()); - enclosingElementsOfInterest.removeAll(result.keySet()); - - Elements elementUtils = processingEnv.getElementUtils(); - enclosingElementsOfInterest.forEach(it -> { - TypeName typeName = it.genericTypeName(); - if (!result.containsKey(typeName)) { - TypeElement element = requireNonNull(elementUtils.getTypeElement(it.name()), it.name()); - result.put(creator.toActivatorImplTypeName(typeName), - utils().toTypeInfo(element, elementsOfInterest::contains).orElseThrow()); - } - }); - } - - private void notifyObservers() { - List observers = HelidonServiceLoader.create(observerLoader()).asList(); - if (!observers.isEmpty()) { - ProcessingEvent event = ProcessingEvent.builder() - .processingEnvironment(processingEnv) - .elementsOfInterest(allElementsOfInterestInThisModule) - .build(); - observers.forEach(it -> it.onProcessingEvent(event)); - } - } - - private Path trackerStatePath() { - return scratchClassOutputPath(targetClassOutputPath(processingEnv.getFiler())) - .resolve(ProcessingTracker.DEFAULT_SCRATCH_FILE_NAME); - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/MessagerToLogAdapter.java b/inject/processor/src/main/java/io/helidon/inject/processor/MessagerToLogAdapter.java deleted file mode 100644 index 23f876b76cd..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/MessagerToLogAdapter.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import io.helidon.inject.tools.Messager; - -class MessagerToLogAdapter implements Messager { - - private final System.Logger logger; - - MessagerToLogAdapter(System.Logger logger) { - this.logger = logger; - } - - @Override - public void debug(String message) { - logger.log(System.Logger.Level.DEBUG, message); - } - - @Override - public void debug(String message, - Throwable t) { - logger.log(System.Logger.Level.DEBUG, message, t); - } - - @Override - public void log(String message) { - logger.log(System.Logger.Level.INFO, message); - } - - @Override - public void warn(String message) { - logger.log(System.Logger.Level.WARNING, message); - } - - @Override - public void warn(String message, - Throwable t) { - logger.log(System.Logger.Level.WARNING, message, t); - } - - @Override - public void error(String message, - Throwable t) { - logger.log(System.Logger.Level.ERROR, message, t); - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/ProcessingEventBlueprint.java b/inject/processor/src/main/java/io/helidon/inject/processor/ProcessingEventBlueprint.java deleted file mode 100644 index fbc7f8208e6..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/ProcessingEventBlueprint.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.Optional; -import java.util.Set; - -import javax.annotation.processing.ProcessingEnvironment; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypedElementInfo; - -/** - * Attributes that can be observed via {@link io.helidon.inject.processor.spi.InjectionAnnotationProcessorObserver}. - */ -@Prototype.Blueprint -interface ProcessingEventBlueprint { - - /** - * Optionally, the active {@link javax.annotation.processing.ProcessingEnvironment} if it is available. - * - * @return the processing environment if it is available - */ - Optional processingEnvironment(); - - /** - * The {@code jakarta.inject.Inject}'able type elements, and possibly any other elements that are found to be of interest for - * processing. The set of processed elements are subject to change in the future. The implementor is therefore encouraged - * to not make assumptions about the set of elements that are in this set. - * - * @return the set of injectable elements, and any other elements of interest to the APT - */ - Set elementsOfInterest(); - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/ProcessingTracker.java b/inject/processor/src/main/java/io/helidon/inject/processor/ProcessingTracker.java deleted file mode 100644 index 04ad21309b2..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/ProcessingTracker.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; - -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.tools.ToolsException; - -/** - * This class adds persistent tracking (typically under ./target/XXX) to allow seamless full and/or incremental processing of - * types to be tracked over repeated compilation cycles over time. It is expected to be integrated into a host annotation - * processor implementation. - *

- * For example, when incremental processing occurs, the elements passed to process in all rounds will just be a subset of - * all of the annotated services since the compiler (from the IDE) only recompiles the files that have been changed. This is - * typically different from how maven invokes compilation (doing a full compile where all types will be seen in the round). The - * {@link InjectionAnnotationProcessor}, for example, would see this reduced subset of types in the round and would otherwise have - * created a {@link ModuleComponent} only representative of the reduced subset of classes. This would be - * incorrect and lead to an invalid module component source file to have been generated. - *

- * We use this tracker to persist the list of generated activators much in the same way that - * {@code META-INF/services} are tracked. A target scratch directory (i.e., target/inject in this case) is used instead - in order - * to keep it out of the build jar. - *

- * Usage: - *

    - *
  1. {@link #initializeFrom} - during the APT initialization phase
  2. - *
  3. {@link #processing(String)} - during each processed type that the annotation processor visits in the round
  4. - *
  5. {@link #removedTypeNames()} or {@link #remainingTypeNames()} as needed - to see the changes over time
  6. - *
  7. {@link #close()} - during final lifecycle of the APT in order to persist state to be (re)written out to disk
  8. - *
- * - * @see InjectionAnnotationProcessor - */ -class ProcessingTracker implements AutoCloseable { - static final String DEFAULT_SCRATCH_FILE_NAME = "activators.lst"; - - private final Path path; - private final Set allTypeNames; - private final TypeElementFinder typeElementFinder; - private final Set foundOrProcessed = new LinkedHashSet<>(); - - /** - * Creates an instance using the given path to keep persistent state. - * - * @param persistentScratchPath the fully qualified path to carry the state - * @param allLines all lines read at initialization - * @param typeElementFinder the type element finder (e.g., {@link ProcessingEnvironment#getElementUtils}) - */ - ProcessingTracker(Path persistentScratchPath, - List allLines, - TypeElementFinder typeElementFinder) { - this.path = persistentScratchPath; - this.allTypeNames = new LinkedHashSet<>(allLines); - this.typeElementFinder = typeElementFinder; - } - - public static ProcessingTracker initializeFrom(Path persistentScratchPath, - ProcessingEnvironment processingEnv) { - List allLines = List.of(); - File file = persistentScratchPath.toFile(); - if (file.exists() && file.canRead()) { - try { - allLines = Files.readAllLines(persistentScratchPath, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new ToolsException(e.getMessage(), e); - } - } - return new ProcessingTracker(persistentScratchPath, allLines, toTypeElementFinder(processingEnv)); - } - - public ProcessingTracker processing(String typeName) { - foundOrProcessed.add(Objects.requireNonNull(typeName)); - return this; - } - - public Set allTypeNamesFromInitialization() { - return allTypeNames; - } - - public Set removedTypeNames() { - Set typeNames = new LinkedHashSet<>(allTypeNamesFromInitialization()); - typeNames.removeAll(remainingTypeNames()); - return typeNames; - } - - public Set remainingTypeNames() { - Set typeNames = new LinkedHashSet<>(allTypeNamesFromInitialization()); - typeNames.addAll(foundOrProcessed); - typeNames.removeIf(typeName -> !found(typeName)); - return typeNames; - } - - @Override - public void close() throws IOException { - Path parent = path.getParent(); - if (parent == null) { - throw new ToolsException("bad path: " + path); - } - Files.createDirectories(parent); - Files.write(path, remainingTypeNames(), StandardCharsets.UTF_8); - } - - private boolean found(String typeName) { - return (typeElementFinder.apply(typeName) != null); - } - - private static TypeElementFinder toTypeElementFinder(ProcessingEnvironment processingEnv) { - return typeName -> processingEnv.getElementUtils().getTypeElement(typeName); - } - - @FunctionalInterface - interface TypeElementFinder extends Function { - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/UnsupportedConstructsProcessor.java b/inject/processor/src/main/java/io/helidon/inject/processor/UnsupportedConstructsProcessor.java deleted file mode 100644 index a8036f3a90f..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/UnsupportedConstructsProcessor.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.Set; -import java.util.stream.Collectors; - -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic; - -import io.helidon.inject.tools.Options; -import io.helidon.inject.tools.TypeNames; - -/** - * When used will recognize constructs that are explicitly known to be unsupported in Injection's reference implementation. - * Examples include: - *
    - *
  • {@code jakarta.annotation.ManagedBean} and "javax.annotation.ManagedBean" - *
  • {@code jakarta.annotation.Resource} and "javax...." - *
  • {@code jakarta.annotation.Resources} and "javax...." - *
  • Any scopes from jakarta.enterprise api module(s) other than ApplicationScoped, which can optionally be mapped to - * Singleton scope. - *
- */ -public class UnsupportedConstructsProcessor extends AbstractProcessor { - private static final System.Logger LOGGER = System.getLogger(UnsupportedConstructsProcessor.class.getName()); - - private static final Set UNSUPPORTED_TARGETS = Set.of( - TypeNames.JAKARTA_MANAGED_BEAN, - TypeNames.JAKARTA_RESOURCE, - TypeNames.JAKARTA_RESOURCES, - TypeNames.JAKARTA_APPLICATION_SCOPED, - TypeNames.JAVAX_APPLICATION_SCOPED, - TypeNames.JAKARTA_CDI_BEFORE_DESTROYED, - TypeNames.JAKARTA_CDI_CONVERSATION_SCOPED, - TypeNames.JAKARTA_CDI_DEPENDENT, - TypeNames.JAKARTA_CDI_DESTROYED, - TypeNames.JAKARTA_CDI_INITIALIZED, - TypeNames.JAKARTA_CDI_NORMAL_SCOPE, - TypeNames.JAKARTA_CDI_REQUEST_SCOPED, - TypeNames.JAKARTA_CDI_SESSION_SCOPED, - TypeNames.JAKARTA_CDI_ACTIVATE_REQUEST_CONTEXT, - TypeNames.JAKARTA_CDI_OBSERVES, - TypeNames.JAKARTA_CDI_OBSERVES_ASYNC, - TypeNames.JAKARTA_CDI_ALTERNATIVE, - TypeNames.JAKARTA_CDI_DISPOSES, - TypeNames.JAKARTA_CDI_INTERCEPTED, - TypeNames.JAKARTA_CDI_MODEL, - TypeNames.JAKARTA_CDI_PRODUCES, - TypeNames.JAKARTA_CDI_SPECIALIZES, - TypeNames.JAKARTA_CDI_STEREOTYPE, - TypeNames.JAKARTA_CDI_TRANSIENT_REFERENCE, - TypeNames.JAKARTA_CDI_TYPED, - TypeNames.JAKARTA_CDI_VETOED, - TypeNames.JAKARTA_CDI_NONBINDING); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public UnsupportedConstructsProcessor() { - } - - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - public Set getSupportedAnnotationTypes() { - return UNSUPPORTED_TARGETS; - } - - @Override - public void init(ProcessingEnvironment processingEnv) { - this.processingEnv = processingEnv; - Options.init(processingEnv); - super.init(processingEnv); - } - - @Override - public boolean process(Set annotations, - RoundEnvironment roundEnv) { - if (!annotations.isEmpty()) { - Set annotationTypeNames = annotations.stream().map(Object::toString).collect(Collectors.toSet()); - if (Options.isOptionEnabled(Options.TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE)) { - annotationTypeNames.remove(TypeNames.JAKARTA_APPLICATION_SCOPED); - annotationTypeNames.remove(TypeNames.JAVAX_APPLICATION_SCOPED); - } - - if (!annotationTypeNames.isEmpty()) { - if (Options.isOptionEnabled(Options.TAG_IGNORE_UNSUPPORTED_ANNOTATIONS)) { - String msg = "ignoring unsupported annotations: " + annotationTypeNames; - LOGGER.log(System.Logger.Level.DEBUG, msg); - processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, msg); - return false; - } - - String msg = "This module contains unsupported annotations for Injection to process: " - + annotationTypeNames + ".\n"; - if (annotationTypeNames.contains(TypeNames.JAKARTA_APPLICATION_SCOPED) - || annotationTypeNames.contains(TypeNames.JAVAX_APPLICATION_SCOPED)) { - msg += "'" + TypeNames.JAKARTA_APPLICATION_SCOPED + "' can be optionally mapped to '" - + TypeNames.JAKARTA_SINGLETON - + "' scope by passing -A" + Options.TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE + "=true.\n"; - } - msg += "Use -A" + Options.TAG_IGNORE_UNSUPPORTED_ANNOTATIONS + "=true to ignore all unsupported annotations."; - - LOGGER.log(System.Logger.Level.ERROR, msg); - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg); - } - } - - return false; - } - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/package-info.java b/inject/processor/src/main/java/io/helidon/inject/processor/package-info.java deleted file mode 100644 index e564d4db0fc..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Annotation Processors and supporting types. - */ -package io.helidon.inject.processor; diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/spi/InjectionAnnotationProcessorObserver.java b/inject/processor/src/main/java/io/helidon/inject/processor/spi/InjectionAnnotationProcessorObserver.java deleted file mode 100644 index c3f5e65c341..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/spi/InjectionAnnotationProcessorObserver.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor.spi; - -import io.helidon.inject.processor.InjectionAnnotationProcessor; -import io.helidon.inject.processor.ProcessingEvent; - -/** - * Implementations of these are service-loaded by the {@link InjectionAnnotationProcessor}, and will be - * called to be able to observe processing events. - */ -public interface InjectionAnnotationProcessorObserver { - - /** - * Called after a processing event that occurred in the {@link InjectionAnnotationProcessor}. - * - * @param event the event - */ - void onProcessingEvent(ProcessingEvent event); - -} diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/spi/package-info.java b/inject/processor/src/main/java/io/helidon/inject/processor/spi/package-info.java deleted file mode 100644 index 96cb69e3520..00000000000 --- a/inject/processor/src/main/java/io/helidon/inject/processor/spi/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection APT SPI package. - */ -package io.helidon.inject.processor.spi; diff --git a/inject/processor/src/main/java/module-info.java b/inject/processor/src/main/java/module-info.java deleted file mode 100644 index cdf2b986e66..00000000000 --- a/inject/processor/src/main/java/module-info.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Annotation Processor module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.processor { - - exports io.helidon.inject.processor.spi; - exports io.helidon.inject.processor; - requires io.helidon.builder.api; - requires io.helidon.common.processor; - requires io.helidon.common; - - requires transitive io.helidon.inject.tools; - requires transitive java.compiler; - - uses io.helidon.inject.processor.spi.InjectionAnnotationProcessorObserver; - uses io.helidon.inject.tools.spi.InterceptorCreator; - uses io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator; - - provides javax.annotation.processing.Processor with - io.helidon.inject.processor.CustomAnnotationProcessor, - io.helidon.inject.processor.UnsupportedConstructsProcessor, - io.helidon.inject.processor.InjectionAnnotationProcessor; - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/CustomAnnotationProcessorTest.java b/inject/processor/src/test/java/io/helidon/inject/processor/CustomAnnotationProcessorTest.java deleted file mode 100644 index bac155e460e..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/CustomAnnotationProcessorTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.ElementKind; - -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypeValues; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.processor.testsubjects.BasicEndpoint; -import io.helidon.inject.processor.testsubjects.ExtensibleGET; -import io.helidon.inject.tools.CustomAnnotationTemplateRequest; -import io.helidon.inject.tools.CustomAnnotationTemplateResponse; -import io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator; - -import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.types.TypeName.create; -import static io.helidon.inject.tools.TypeTools.createAnnotationListFromAnnotations; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasKey; -import static org.hamcrest.Matchers.is; - -class CustomAnnotationProcessorTest { - - @Test - @SuppressWarnings("unchecked") - void annotationSupported() { - CustomAnnotationProcessor processor = new CustomAnnotationProcessor(); - assertThat(processor.getSupportedAnnotationTypes(), - containsInAnyOrder(ExtensibleGET.class.getName())); - } - - @Test - void extensibleGET() { - CustomAnnotationProcessor processor = new CustomAnnotationProcessor(); - - List annotations = createAnnotationListFromAnnotations(BasicEndpoint.class.getAnnotations()); - TypeInfo enclosingTypeInfo = TypeInfo.builder() - .typeKind(TypeValues.KIND_CLASS) - .typeName(create(BasicEndpoint.class)) - .annotations(annotations) - .build(); - TypedElementInfo target = TypedElementInfo.builder() - .typeName(create(String.class)) - .elementTypeKind(ElementKind.METHOD.name()) - .elementName("itWorks") - .build(); - TypedElementInfo arg1 = TypedElementInfo.builder() - .typeName(create(String.class)) - .elementName("header") - .elementTypeKind(TypeValues.KIND_PARAMETER) - .build(); - ServiceInfoBasics serviceInfo = ServiceInfo.builder() - .serviceTypeName(BasicEndpoint.class) - .build(); - GenericTemplateCreatorDefault genericTemplateCreator = - new GenericTemplateCreatorDefault(ExtensibleGetTemplateProducer.class); - CustomAnnotationTemplateRequest req = CustomAnnotationTemplateRequest.builder() - .annoTypeName(create(ExtensibleGET.class)) - .serviceInfo(serviceInfo) - .targetElement(target) - .targetElementArgs(List.of(arg1)) - .targetElementAccess(AccessModifier.PUBLIC) - .enclosingTypeInfo(enclosingTypeInfo) - .genericTemplateCreator(genericTemplateCreator) - .build(); - assertThat(req.isFilerEnabled(), is(true)); - - Set producers = processor.producersForType(req.annoTypeName()); - assertThat(producers.size(), equalTo(1)); - - CustomAnnotationTemplateResponse res = processor.process(producers.iterator().next(), req); - assertThat(res.request().annoTypeName().name(), equalTo(ExtensibleGET.class.getName())); - TypeName generatedTypeName = - TypeName.create("io.helidon.inject.processor.testsubjects.BasicEndpoint_ExtensibleGET_itWorks"); - assertThat(res.generatedSourceCode(), - hasKey(generatedTypeName)); - assertThat(res.toString(), res.generatedSourceCode().size(), - is(1)); - String generatedSource = res.generatedSourceCode().get(generatedTypeName); - MatcherAssert.assertThat(generatedSource, - equalTo(TestUtils.loadStringFromResource("expected/BasicEndpoint_ExtensibleGET._java_"))); - } - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/ExtensibleGetTemplateProducer.java b/inject/processor/src/test/java/io/helidon/inject/processor/ExtensibleGetTemplateProducer.java deleted file mode 100644 index a31259e7324..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/ExtensibleGetTemplateProducer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.inject.tools.CustomAnnotationTemplateRequest; -import io.helidon.inject.tools.CustomAnnotationTemplateResponse; -import io.helidon.inject.tools.GenericTemplateCreatorRequest; -import io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator; - -/** - * For Testing (service loaded). - */ -// Note: if we uncomment this @Singleton, a compile-time activator will be built - we want to avoid that here -//@Singleton -public class ExtensibleGetTemplateProducer implements CustomAnnotationTemplateCreator { - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public ExtensibleGetTemplateProducer() { - assert (true); // for setting breakpoints in debug - } - - @Override - public Set annoTypes() { - return Set.of(TypeName.create("io.helidon.inject.processor.testsubjects.ExtensibleGET")); - } - - @Override - public Optional create(CustomAnnotationTemplateRequest request) { - TypeInfo enclosingTypeInfo = request.enclosingTypeInfo(); - String classname = enclosingTypeInfo.typeName().className() + "_" - + request.annoTypeName().className() + "_" - + request.targetElement().elementName(); - TypeName generatedTypeName = TypeName.builder(enclosingTypeInfo.typeName()) - .className(classname) - .build(); - GenericTemplateCreatorDefault genericTemplateCreator = new GenericTemplateCreatorDefault(getClass()); - CharSequence template = genericTemplateCreator.supplyFromResources("helidon", "extensible-get.hbs"); - GenericTemplateCreatorRequest genericCreatorRequest = GenericTemplateCreatorRequest.builder() - .customAnnotationTemplateRequest(request) - .generatedTypeName(generatedTypeName) - .template(template) - .build(); - return genericTemplateCreator.create(genericCreatorRequest); - } - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/ProcessingTrackerTest.java b/inject/processor/src/test/java/io/helidon/inject/processor/ProcessingTrackerTest.java deleted file mode 100644 index 6a3583fe6d1..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/ProcessingTrackerTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.util.List; - -import javax.lang.model.element.TypeElement; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.mockito.Mockito.mock; - -class ProcessingTrackerTest { - - @Test - void noDelta() { - List typeNames = List.of("a", "b", "c"); - ProcessingTracker tracker = new ProcessingTracker(null, typeNames, - typeName -> mock(TypeElement.class)); - assertThat(tracker.removedTypeNames().size(), - is(0)); - assertThat(tracker.remainingTypeNames(), - containsInAnyOrder("a", "b", "c")); - } - - @Test - void incrementalCompilation() { - List typeNames = List.of("a", "b", "c"); - ProcessingTracker tracker = new ProcessingTracker(null, typeNames, - typeName -> mock(TypeElement.class)); - tracker.processing("b"); - - assertThat(tracker.removedTypeNames().size(), - is(0)); - assertThat(tracker.remainingTypeNames(), - containsInAnyOrder("a", "b", "c")); - } - - @Test - void incrementalCompilationWithFilesRemoved() { - List typeNames = List.of("a", "b", "c"); - ProcessingTracker tracker = new ProcessingTracker(null, typeNames, - typeName -> (typeName.equals("b") ? null : mock(TypeElement.class))); - - assertThat(tracker.removedTypeNames().size(), - is(1)); - assertThat(tracker.remainingTypeNames(), - containsInAnyOrder("a", "c")); - } - - @Test - void incrementalCompilationWithFilesAddedAndRemoved() { - List typeNames = List.of("a"); - ProcessingTracker tracker = new ProcessingTracker(null, typeNames, - typeName -> mock(TypeElement.class)); - tracker.processing("b"); - tracker.processing("a"); - - assertThat(tracker.removedTypeNames().size(), - is(0)); - assertThat(tracker.remainingTypeNames(), - containsInAnyOrder("a", "b")); - } - - @Test - void cleanCompilation() { - List typeNames = List.of(); - ProcessingTracker tracker = new ProcessingTracker(null, typeNames, - typeName -> mock(TypeElement.class)); - tracker.processing("a"); - tracker.processing("b"); - tracker.processing("c"); - - assertThat(tracker.removedTypeNames().size(), - is(0)); - assertThat(tracker.remainingTypeNames(), - containsInAnyOrder("a", "b", "c")); - } - - @Test - void fullCompilationWithFilesAdded() { - List typeNames = List.of("a"); - ProcessingTracker tracker = new ProcessingTracker(null, typeNames, - typeName -> mock(TypeElement.class)); - tracker.processing("a"); - tracker.processing("b"); - tracker.processing("c"); - - assertThat(tracker.removedTypeNames().size(), - is(0)); - assertThat(tracker.remainingTypeNames(), - containsInAnyOrder("a", "b", "c")); - } - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/TestUtils.java b/inject/processor/src/test/java/io/helidon/inject/processor/TestUtils.java deleted file mode 100644 index 525727f1c59..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/TestUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - -import io.helidon.inject.tools.ToolsException; - -/** - * Testing utilities. - */ -class TestUtils { - - private TestUtils() { - } - - /** - * Load string from resource. - * - * @param resourceNamePath the resource path - * @return the loaded string - */ - static String loadStringFromResource(String resourceNamePath) { - try { - try (InputStream in = TestUtils.class.getClassLoader().getResourceAsStream(resourceNamePath)) { - return new String(in.readAllBytes(), StandardCharsets.UTF_8); - } - } catch (Exception e) { - throw new ToolsException("Failed to load: " + resourceNamePath, e); - } - } - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/package-info.java b/inject/processor/src/test/java/io/helidon/inject/processor/package-info.java deleted file mode 100644 index 1db287a74a4..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Annotation processing testing related types. - */ -package io.helidon.inject.processor; diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/BasicEndpoint.java b/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/BasicEndpoint.java deleted file mode 100644 index 7fcc7222f5f..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/BasicEndpoint.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor.testsubjects; - -import jakarta.inject.Singleton; - -/** - * For Testing. - */ -@Singleton -@BasicPath("/*") -public class BasicEndpoint { - - /** - * For testing. - * - * @param header for testing - * @return for testing - */ - @ExtensibleGET - public String itWorks(String header) { - return "Injection Works!"; - } - - @ExtensibleGET - @BasicPath("/whatever/*") - public String itWorks2() { - return "Injection Works 2!"; - } - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/BasicPath.java b/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/BasicPath.java deleted file mode 100644 index 16d53d64036..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/BasicPath.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor.testsubjects; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * For Testing. - */ -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.CLASS) -@Documented -public @interface BasicPath { - - /** - * Path to use, defaults to {@code /}. - * - * @return path to use - */ - String value() default "/"; - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/ExtensibleGET.java b/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/ExtensibleGET.java deleted file mode 100644 index ac827398185..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/ExtensibleGET.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.processor.testsubjects; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * For Testing. - */ -@Retention(RetentionPolicy.CLASS) -@Documented -public @interface ExtensibleGET { - -} diff --git a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/package-info.java b/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/package-info.java deleted file mode 100644 index 38ce041f652..00000000000 --- a/inject/processor/src/test/java/io/helidon/inject/processor/testsubjects/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Test subjects for annotation processing. - */ -package io.helidon.inject.processor.testsubjects; diff --git a/inject/processor/src/test/resources/META-INF/services/io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator b/inject/processor/src/test/resources/META-INF/services/io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator deleted file mode 100644 index 1d6ade5a78d..00000000000 --- a/inject/processor/src/test/resources/META-INF/services/io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator +++ /dev/null @@ -1 +0,0 @@ -io.helidon.inject.processor.ExtensibleGetTemplateProducer diff --git a/inject/processor/src/test/resources/expected/BasicEndpoint_ExtensibleGET._java_ b/inject/processor/src/test/resources/expected/BasicEndpoint_ExtensibleGET._java_ deleted file mode 100644 index 1f049604476..00000000000 --- a/inject/processor/src/test/resources/expected/BasicEndpoint_ExtensibleGET._java_ +++ /dev/null @@ -1,27 +0,0 @@ -package io.helidon.inject.processor.testsubjects; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@io.helidon.common.Generated(value = "io.helidon.inject.processor.ExtensibleGetTemplateProducer", trigger = "io.helidon.inject.processor.testsubjects.BasicEndpoint") -@Singleton -@Named("io.helidon.inject.processor.testsubjects.ExtensibleGET") -@Weight(100.0) -public class BasicEndpoint_ExtensibleGET_itWorks { - private final Provider target; - - @Inject - BasicEndpoint_ExtensibleGET_itWorks(Provider target) { - this.target = target; - } - - public Provider getBasicEndpoint() { - return target; - } - -} diff --git a/inject/processor/src/test/resources/templates/inject/helidon/extensible-get.hbs b/inject/processor/src/test/resources/templates/inject/helidon/extensible-get.hbs deleted file mode 100644 index ad4a93ae0df..00000000000 --- a/inject/processor/src/test/resources/templates/inject/helidon/extensible-get.hbs +++ /dev/null @@ -1,41 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}package {{packageName}}; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -{{{generatedSticker}}} -@Singleton -@Named("{{annoTypeName}}") -@Weight({{weight}}) -public class {{className}} { - private final Provider<{{enclosingClassTypeName.className}}> target; - - @Inject - {{className}}(Provider<{{enclosingClassTypeName.className}}> target) { - this.target = target; - } - - public Provider<{{enclosingClassTypeName.className}}> get{{enclosingClassTypeName.className}}() { - return target; - } - -} diff --git a/inject/runtime/README.md b/inject/runtime/README.md deleted file mode 100644 index aadc77e53e7..00000000000 --- a/inject/runtime/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# inject-runtime - -This module represents the main runtime support for default [Injection API/SPI](../inject) services implementation. diff --git a/inject/runtime/pom.xml b/inject/runtime/pom.xml deleted file mode 100644 index 01489d8c3d7..00000000000 --- a/inject/runtime/pom.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-runtime - Helidon Injection Runtime Services - - - - io.helidon - helidon - - - io.helidon.inject - helidon-inject-api - - - jakarta.inject - jakarta.inject-api - compile - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.config - helidon-config-metadata - true - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - - - - - diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/AbstractServiceProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/AbstractServiceProvider.java deleted file mode 100644 index 0a76b088a91..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/AbstractServiceProvider.java +++ /dev/null @@ -1,1412 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ActivationLog; -import io.helidon.inject.api.ActivationLogEntry; -import io.helidon.inject.api.ActivationPhaseReceiver; -import io.helidon.inject.api.ActivationRequest; -import io.helidon.inject.api.ActivationResult; -import io.helidon.inject.api.ActivationStatus; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.DeActivationRequest; -import io.helidon.inject.api.DeActivator; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.Event; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesConfig; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.PostConstructMethod; -import io.helidon.inject.api.PreDestroyMethod; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceInjectionPlanBinder; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; -import io.helidon.inject.api.ServiceProviderInjectionException; -import io.helidon.inject.spi.InjectionResolver; - -import jakarta.inject.Provider; - -/** - * Abstract base implementation for {@link ServiceProviderBindable}, which represents the basics for regular - * Singleton, ApplicationScoped, Provider, and ServiceProvider based managed services. All code-generated services will - * extend from this abstract base class. - * - * @param the type of the service this provider manages - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public abstract class AbstractServiceProvider - implements ServiceProviderBindable, - Activator, - DeActivator, - ActivationPhaseReceiver, - Resettable { - static final DependenciesInfo NO_DEPS = DependenciesInfo.builder().build(); - private static final System.Logger LOGGER = System.getLogger(AbstractServiceProvider.class.getName()); - - private final Semaphore activationSemaphore = new Semaphore(1); - private final AtomicReference serviceRef = new AtomicReference<>(); - private Phase phase; - private long lastActivationThreadId; - private InjectionServices injectionServices; - private ActivationLog log; - private ServiceInfo serviceInfo; - private DependenciesInfo dependencies; - private Map injectionPlan; - private ServiceProvider interceptor; - private boolean thisIsAnInterceptor; - - /** - * The default constructor. - */ - protected AbstractServiceProvider() { - this.phase = Phase.INIT; - } - - /** - * Constructor. - * - * @param instance the managed service instance - * @param phase the current phase - * @param serviceInfo the service info - * @param injectionServices the services instance - */ - protected AbstractServiceProvider(T instance, - Phase phase, - ServiceInfo serviceInfo, - InjectionServices injectionServices) { - this(); - if (instance != null) { - this.serviceRef.set(instance); - this.phase = (phase != null) ? phase : Phase.ACTIVE; - } - this.serviceInfo = ServiceInfo.builder(serviceInfo).build(); - this.injectionServices = Objects.requireNonNull(injectionServices); - this.log = injectionServices.activationLog().orElseThrow(); - onInitialized(); - } - - /** - * Will test and downcast the passed service provider to an instance of - * {@link AbstractServiceProvider}. - * - * @param sp the service provider - * @param expected is the result expected to be present - * @param the managed service type - * @return the abstract service provider - */ - @SuppressWarnings("unchecked") - public static Optional> toAbstractServiceProvider(ServiceProvider sp, - boolean expected) { - if (!(sp instanceof AbstractServiceProvider)) { - if (expected) { - throw new IllegalStateException("Expected provider to be of type " + AbstractServiceProvider.class.getName()); - } - return Optional.empty(); - } - return Optional.of((AbstractServiceProvider) sp); - } - - @Override - public Optional activator() { - return Optional.of(this); - } - - @Override - public Optional deActivator() { - return Optional.of(this); - } - - @Override - public Optional> serviceProviderBindable() { - return Optional.of(this); - } - - @Override - public boolean isProvider() { - return false; - } - - /** - * Identifies whether the implementation was custom written and not code generated. We assume by default this is part - * of code-generation, and the default is to return false. - * - * @return true if a custom, user-supplied implementation (rare) - */ - public boolean isCustom() { - return false; - } - - @Override - public ServiceInfo serviceInfo() { - return Objects.requireNonNull(serviceInfo, getClass().getName() + " should have been initialized."); - } - - @Override - public DependenciesInfo dependencies() { - return (dependencies == null) ? NO_DEPS : dependencies; - } - - @Override - public double weight() { - return serviceInfo().realizedWeight(); - } - - @Override - public Phase currentActivationPhase() { - return phase; - } - - @Override - public Optional injectionServices() { - return Optional.ofNullable(injectionServices); - } - - InjectionServices requiredInjectionServices() { - return injectionServices() - .orElseThrow(() -> new InjectionServiceProviderException(description() - + ": injectionServices should have been previously set", - this)); - } - - @Override - public void injectionServices(Optional injectionServices) { - if (injectionServices.isPresent() - || serviceRef.get() != null) { - InjectionServices current = this.injectionServices; - if (injectionServices.orElse(null) == current) { - return; - } - - if (current != null) { - if (current.config().permitsDynamic()) { - reset(true); - } else { - throw alreadyInitialized(); - } - } - } - - this.injectionServices = injectionServices.orElse(null); - this.phase = Phase.INIT; - if (this.injectionServices != null) { - onInitialized(); - } - } - - @Override - public void moduleName(String moduleName) { - Objects.requireNonNull(moduleName); - ServiceInfo serviceInfo = serviceInfo(); - String moduleInfoName = serviceInfo.moduleName().orElse(null); - if (!Objects.equals(moduleInfoName, moduleName)) { - if (moduleInfoName != null) { - throw alreadyInitialized(); - } - this.serviceInfo = ServiceInfo.builder(serviceInfo).moduleName(moduleName).build(); - } - } - - @Override - public boolean isInterceptor() { - return thisIsAnInterceptor; - } - - @Override - public Optional> interceptor() { - return Optional.ofNullable(interceptor); - } - - @Override - public void interceptor(ServiceProvider interceptor) { - Objects.requireNonNull(interceptor); - if (this.interceptor != null || activationSemaphore.availablePermits() == 0 || phase != Phase.INIT) { - throw alreadyInitialized(); - } - this.interceptor = interceptor; - if (interceptor instanceof AbstractServiceProvider) { - ((AbstractServiceProvider) interceptor).intercepted(this); - } - } - - /** - * Incorporate the intercepted qualifiers into our own qualifiers. - * - * @param intercepted the service being intercepted - */ - void intercepted(AbstractServiceProvider intercepted) { - if (activationSemaphore.availablePermits() == 0 || phase != Phase.INIT) { - throw alreadyInitialized(); - } - this.thisIsAnInterceptor = true; - this.serviceInfo = ServiceInfo.builder(this.serviceInfo) - .addQualifiers(intercepted.serviceInfo().qualifiers()) - .build(); - } - - @Override - public int hashCode() { - return System.identityHashCode(serviceInfo.serviceTypeName()); - } - - @Override - public boolean equals(Object another) { - return (another instanceof ServiceProvider) - && id().equals(((ServiceProvider) another).id()) - && serviceInfo().equals(((ServiceProvider) another).serviceInfo()); - } - - @Override - public String toString() { - return description(); - } - - @Override - public String description() { - return name(true) + identitySuffix() + ":" + currentActivationPhase(); - } - - @Override - public String id() { - return identityPrefix() + name(false) + identitySuffix(); - } - - /** - * The name assigned to this provider. Simple names are not unique. - * - * @param simple flag to indicate simple name usage - * @return this name assigned to this provider - */ - public String name(boolean simple) { - TypeName name = serviceInfo().serviceTypeName(); - return (simple) ? name.classNameWithEnclosingNames().replace('.', '$') : name.resolvedName(); - } - - @Override - public T get() { - return first(InjectionServices.SERVICE_QUERY_REQUIRED) - .orElseThrow(() -> new InjectionServiceProviderException("Expected to find a match", this)); - } - - @SuppressWarnings("unchecked") - @Override - public Optional first(ContextualServiceQuery ctx) { - T serviceOrProvider = maybeActivate(ctx).orElse(null); - - try { - if (isProvider()) { - T instance; - - if (serviceOrProvider instanceof InjectionPointProvider) { - instance = ((InjectionPointProvider) serviceOrProvider).first(ctx).orElse(null); - } else if (serviceOrProvider instanceof Provider) { - instance = ((Provider) serviceOrProvider).get(); - if (ctx.expected() && instance == null) { - throw expectedQualifiedServiceError(ctx); - } - } else { - instance = NonSingletonServiceProvider.createAndActivate(this); - } - - if (ctx.expected() && instance == null) { - throw new InjectionServiceProviderException("Expected to find a match: " + ctx, this); - } - - return Optional.ofNullable(instance); - } - } catch (ServiceProviderInjectionException ie) { - throw ie; - } catch (Throwable t) { - logger().log(System.Logger.Level.ERROR, "unable to activate: " + getClass().getName(), t); - throw unableToActivate(t); - } - - return Optional.ofNullable(serviceOrProvider); - } - - @SuppressWarnings("unchecked") - @Override - public List list(ContextualServiceQuery ctx) { - T serviceProvider = maybeActivate(ctx).orElse(null); - - try { - if (isProvider()) { - List instances = null; - - if (serviceProvider instanceof InjectionPointProvider) { - instances = ((InjectionPointProvider) serviceProvider).list(ctx); - } else if (serviceProvider instanceof Provider) { - T instance = ((Provider) serviceProvider).get(); - if (ctx.expected() && instance == null) { - throw expectedQualifiedServiceError(ctx); - } - if (instance != null) { - if (instance instanceof List) { - instances = (List) instance; - } else { - instances = List.of(instance); - } - } - } else { - T instance = NonSingletonServiceProvider.createAndActivate(this); - instances = List.of(instance); - } - - return instances; - } - } catch (ServiceProviderInjectionException ie) { - throw ie; - } catch (Throwable t) { - throw unableToActivate(t); - } - - return (serviceProvider != null) ? List.of(serviceProvider) : List.of(); - } - - @Override - public ActivationResult activate(ActivationRequest req) { - if (isAlreadyAtTargetPhase(req.targetPhase())) { - return ActivationResult.builder() - .serviceProvider(this) - .startingActivationPhase(currentActivationPhase()) - .finishingActivationPhase(currentActivationPhase()) - .targetActivationPhase(currentActivationPhase()) - .finishingStatus(ActivationStatus.SUCCESS) - .build(); - } - - LogEntryAndResult logEntryAndResult = preambleActivate(req); - ActivationResult.Builder res = logEntryAndResult.activationResult; - - // if we get here then we own the semaphore for activation... - try { - Phase finishing = res.finishingActivationPhase().orElse(null); - if (res.targetActivationPhase().ordinal() >= Phase.ACTIVATION_STARTING.ordinal() - && (Phase.INIT == res.finishingActivationPhase().orElse(null) - || Phase.PENDING == finishing - || Phase.ACTIVATION_STARTING == finishing - || Phase.DESTROYED == finishing)) { - doStartingLifecycle(logEntryAndResult); - } - finishing = res.finishingActivationPhase().orElse(null); - if (res.targetActivationPhase().ordinal() >= Phase.GATHERING_DEPENDENCIES.ordinal() - && (Phase.ACTIVATION_STARTING == finishing)) { - doGatheringDependencies(logEntryAndResult); - } - finishing = res.finishingActivationPhase().orElse(null); - if (res.targetActivationPhase().ordinal() >= Phase.CONSTRUCTING.ordinal() - && (Phase.GATHERING_DEPENDENCIES == finishing)) { - doConstructing(logEntryAndResult); - } - finishing = res.finishingActivationPhase().orElse(null); - if (res.targetActivationPhase().ordinal() >= Phase.INJECTING.ordinal() - && (Phase.CONSTRUCTING == finishing)) { - doInjecting(logEntryAndResult); - } - finishing = res.finishingActivationPhase().orElse(null); - if (res.targetActivationPhase().ordinal() >= Phase.POST_CONSTRUCTING.ordinal() - && (Phase.INJECTING == finishing)) { - doPostConstructing(logEntryAndResult); - } - finishing = res.finishingActivationPhase().orElse(null); - if (res.targetActivationPhase().ordinal() >= Phase.ACTIVATION_FINISHING.ordinal() - && (Phase.POST_CONSTRUCTING == finishing)) { - doActivationFinishing(logEntryAndResult); - } - finishing = res.finishingActivationPhase().orElse(null); - if (res.targetActivationPhase().ordinal() >= Phase.ACTIVE.ordinal() - && (Phase.ACTIVATION_FINISHING == finishing)) { - doActivationActive(logEntryAndResult); - } - - onFinished(logEntryAndResult); - } catch (Throwable t) { - onFailedFinish(logEntryAndResult, t, req.throwIfError()); - } finally { - this.lastActivationThreadId = 0; - activationSemaphore.release(); - } - - return logEntryAndResult.activationResult.build(); - } - - @Override - public void onPhaseEvent(Event event, - Phase phase) { - // NOP - } - - /** - * Called at startup to establish the injection plan as an alternative to gathering it dynamically. - */ - @Override - public Optional injectionPlanBinder() { - if (dependencies == null) { - dependencies(dependencies()); - - if (dependencies == null) { - // couldn't accept our suggested dependencies - return Optional.empty(); - } - } - - if (injectionPlan != null) { - logger().log(System.Logger.Level.WARNING, - "this service provider already has an injection plan (which is unusual here): " + this); - } - - ConcurrentHashMap idToIpInfo = new ConcurrentHashMap<>(); - dependencies.allDependencies() - .forEach(dep -> - dep.injectionPointDependencies().forEach(ipDep -> { - String id = ipDep.id(); - InjectionPointInfo prev = idToIpInfo.put(id, ipDep); - if (prev != null - && !prev.equals(ipDep) - && !prev.dependencyToServiceInfo().equals(ipDep.dependencyToServiceInfo())) { - logMultiDefInjectionNote(id, prev, ipDep); - } - })); - - ConcurrentHashMap injectionPlan = new ConcurrentHashMap<>(); - AbstractServiceProvider self = AbstractServiceProvider.this; - ServiceInjectionPlanBinder.Binder result = new ServiceInjectionPlanBinder.Binder() { - private InjectionPointInfo ipInfo; - - @Override - public ServiceInjectionPlanBinder.Binder bind(String id, - ServiceProvider serviceProvider) { - HelidonInjectionPlan plan = createBuilder(id) - .injectionPointQualifiedServiceProviders(List.of(bind(serviceProvider))) - .build(); - Object prev = injectionPlan.put(id, plan); - assert (prev == null); - return this; - } - - @Override - public ServiceInjectionPlanBinder.Binder bindMany(String id, - ServiceProvider... serviceProviders) { - HelidonInjectionPlan plan = createBuilder(id) - .injectionPointQualifiedServiceProviders(bind(Arrays.asList(serviceProviders))) - .build(); - Object prev = injectionPlan.put(id, plan); - assert (prev == null); - return this; - } - - @Override - public ServiceInjectionPlanBinder.Binder bindVoid(String id) { - return bind(id, VoidServiceProvider.INSTANCE); - } - - @Override - public ServiceInjectionPlanBinder.Binder resolvedBind(String id, - Class serviceType) { - try { - InjectionResolver resolver = (InjectionResolver) AbstractServiceProvider.this; - TypeName typeName = TypeName.create(serviceType); - ServiceInfoCriteria serviceInfo = ServiceInfoCriteria.builder() - .serviceTypeName(typeName) - .build(); - - InjectionPointInfo ipInfo = InjectionPointInfo.builder() - .id(id) - .dependencyToServiceInfo(serviceInfo) - // the following values are required, but dummy in this instance - .elementKind(ElementKind.METHOD) - .elementTypeName(typeName) - .elementName("none") - .serviceTypeName(typeName) - .access(AccessModifier.PUBLIC) - .ipType(typeName) - .ipName("none") - .baseIdentity("none") - .build(); - Object resolved = Objects.requireNonNull( - resolver.resolve(ipInfo, requiredInjectionServices(), AbstractServiceProvider.this, false)); - HelidonInjectionPlan plan = createBuilder(id) - .unqualifiedProviders(List.of(resolved)) - .resolved(false) - .build(); - Object prev = injectionPlan.put(id, plan); - assert (prev == null); - return this; - } catch (Exception e) { - throw new InjectionServiceProviderException("Failed to process: " + id, e, AbstractServiceProvider.this); - } - } - - @Override - public void commit() { - if (!idToIpInfo.isEmpty()) { - throw new ServiceProviderInjectionException("Missing injection bindings for " - + idToIpInfo + " in " - + this, null, self); - } - - if ((self.injectionPlan != null) && !self.injectionPlan.equals(injectionPlan)) { - throw new ServiceProviderInjectionException("Injection plan has already been bound for " + this, null, self); - } - self.injectionPlan = injectionPlan; - } - - private ServiceProvider bind(ServiceProvider rawSp) { - assert (!(rawSp instanceof BoundedServiceProvider)) : rawSp; - return BoundedServiceProvider.create(rawSp, ipInfo); - } - - private List> bind(List> rawList) { - return rawList.stream().map(this::bind).collect(Collectors.toList()); - } - - private InjectionPointInfo safeGetIpInfo(String id) { - InjectionPointInfo ipInfo = idToIpInfo.remove(id); - if (ipInfo == null) { - throw new ServiceProviderInjectionException("Expected to find a dependency for '" + id + "' from " - + this + " in " + idToIpInfo, null, self); - } - return ipInfo; - } - - private HelidonInjectionPlan.Builder createBuilder(String id) { - ipInfo = safeGetIpInfo(id); - return HelidonInjectionPlan.builder() - .injectionPointInfo(ipInfo) - .serviceProvider(self); - } - }; - - return Optional.of(result); - } - - /** - * Get or Create the injection plan. - * - * @param resolveIps true if the injection points should also be activated/resolved. - * @return the injection plan - */ - public Map getOrCreateInjectionPlan(boolean resolveIps) { - if (this.injectionPlan != null) { - return this.injectionPlan; - } - - if (this.dependencies == null) { - dependencies(dependencies()); - } - - Map plan = DefaultInjectionPlans - .createInjectionPlans(requiredInjectionServices(), this, dependencies, resolveIps, logger()); - assert (this.injectionPlan == null); - this.injectionPlan = Objects.requireNonNull(plan); - - return this.injectionPlan; - } - - @Override - public boolean reset(boolean deep) { - Object service = serviceRef.get(); - boolean result = false; - boolean didAcquire = false; - try { - didAcquire = activationSemaphore.tryAcquire(1, TimeUnit.MILLISECONDS); - - if (service != null) { - System.Logger.Level level = ( - InjectionServices.injectionServices().map(InjectionServices::config) - .map(InjectionServicesConfig::shouldDebug) - .orElse(false)) - ? System.Logger.Level.INFO : System.Logger.Level.DEBUG; - logger().log(level, "Resetting " + this); - if (deep && service instanceof Resettable) { - try { - if (((Resettable) service).reset(deep)) { - result = true; - } - } catch (Throwable t) { - logger().log(System.Logger.Level.WARNING, "Unable to reset: " + this, t); // eat it - } - } - } - - if (deep) { - injectionPlan = null; - interceptor = null; - injectionServices = null; - serviceRef.set(null); - phase = Phase.INIT; - - result = true; - } - } catch (Exception e) { - if (didAcquire) { - throw new InjectionServiceProviderException("Unable to reset", e, this); - } else { - throw new InjectionServiceProviderException("Unable to reset during activation", e, this); - } - } finally { - if (didAcquire) { - activationSemaphore.release(); - } - } - - return result; - } - - @Override - public Optional postConstructMethod() { - return Optional.empty(); - } - - @Override - public Optional preDestroyMethod() { - return Optional.empty(); - } - - @Override - public ActivationResult deactivate(DeActivationRequest req) { - if (!currentActivationPhase().eligibleForDeactivation()) { - return ActivationResult.builder() - .serviceProvider(this) - .startingActivationPhase(currentActivationPhase()) - .finishingActivationPhase(currentActivationPhase()) - .targetActivationPhase(currentActivationPhase()) - .finishingStatus(ActivationStatus.SUCCESS) - .build(); - } - - InjectionServices injectionServices = requiredInjectionServices(); - InjectionServicesConfig cfg = injectionServices.config(); - - // if we are here then we are not yet at the ultimate target phase, and we either have to activate or deactivate - LogEntryAndResult logEntryAndResult = createLogEntryAndResult(Phase.DESTROYED); - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.PRE_DESTROYING); - - boolean didAcquire = false; - try { - // let's wait a bit on the semaphore until we read timeout (probably detecting a deadlock situation) - if (!activationSemaphore.tryAcquire(cfg.activationDeadlockDetectionTimeout().toMillis(), TimeUnit.MILLISECONDS)) { - // if we couldn't grab the semaphore than we (or someone else) is busy activating this services, or - // we deadlocked. - ServiceProviderInjectionException e = timedOutDeActivationInjectionError(logEntryAndResult.logEntry); - onFailedFinish(logEntryAndResult, e, req.throwIfError()); - return logEntryAndResult.activationResult.build(); - } - didAcquire = true; - - // if we made it to here then we "own" the semaphore and the subsequent activation steps - this.lastActivationThreadId = Thread.currentThread().getId(); - - doPreDestroying(logEntryAndResult); - if (Phase.PRE_DESTROYING == logEntryAndResult.activationResult.finishingActivationPhase().orElse(null)) { - doDestroying(logEntryAndResult); - } - onFinished(logEntryAndResult); - } catch (Throwable t) { - ServiceProviderInjectionException e = interruptedPreActivationInjectionError(logEntryAndResult.logEntry, t); - onFailedFinish(logEntryAndResult, e, req.throwIfError()); - } finally { - if (didAcquire) { - activationSemaphore.release(); - } - onFinalShutdown(); - } - - return logEntryAndResult.activationResult.build(); - } - - /** - * Called on the final leg of the shutdown sequence. - */ - protected void onFinalShutdown() { - this.lastActivationThreadId = 0; - this.injectionPlan = null; - this.phase = Phase.DESTROYED; - this.serviceRef.set(null); - this.injectionServices = null; - this.log = null; - } - - /** - * Called on a failed finish of activation. - * - * @param logEntryAndResult the log entry holding the result - * @param t the error that was observed - * @param throwOnError the flag indicating whether we should throw on error - * @see #onFinished(AbstractServiceProvider.LogEntryAndResult) - */ - protected void onFailedFinish(LogEntryAndResult logEntryAndResult, - Throwable t, - boolean throwOnError) { - this.lastActivationThreadId = 0; - onFailedFinish(logEntryAndResult, t, throwOnError, activationLog()); - } - - /** - * The logger. - * - * @return the logger - */ - protected System.Logger logger() { - return LOGGER; - } - - /** - * Sets the service info that describes the managed service that is assigned. - * - * @param serviceInfo the service info - */ - protected void serviceInfo(ServiceInfo serviceInfo) { - Objects.requireNonNull(serviceInfo); - if (this.injectionServices != null && this.serviceInfo != null) { - throw alreadyInitialized(); - } - this.serviceInfo = serviceInfo; - } - - /** - * Used to set the dependencies from this service provider. - * - * @param dependencies the dependencies from this service provider - */ - protected void dependencies(DependenciesInfo dependencies) { - Objects.requireNonNull(dependencies); - if (this.dependencies != null) { - throw alreadyInitialized(); - } - this.dependencies = dependencies; - } - - /** - * Returns true if the current activation phase has reached the given target phase. - * - * @param targetPhase the target phase - * @return true if the targetPhase has been reached - */ - protected boolean isAlreadyAtTargetPhase(Phase targetPhase) { - Objects.requireNonNull(targetPhase); - return (currentActivationPhase() == targetPhase); - } - - /** - * The identity prefix, or empty string if there is no prefix. - * - * @return the identity prefix - */ - protected String identityPrefix() { - return ""; - } - - /** - * The identity suffix, or empty string if there is no suffix. - * - * @return the identity suffix - */ - protected String identitySuffix() { - return ""; - } - - /** - * Returns the managed service this provider has (or is in the process of) activating. - * - * @return the service we are managing lifecycle for - */ - protected Optional serviceRef() { - return Optional.ofNullable(serviceRef.get()); - } - - /** - * Returns the activation log. - * - * @return the activation log - */ - protected Optional activationLog() { - if (log == null && injectionServices != null) { - log = injectionServices.activationLog().orElse(DefaultActivationLog.createUnretainedLog(logger())); - } - return Optional.ofNullable(log); - } - - /** - * Called by the generated code when it is attempting to resolve a specific injection point dependency by id. - * - * @param deps the entire map of resolved dependencies - * @param id the id of the dependency to lookup - * @param the type of the dependency - * @return the resolved object - */ - protected T get(Map deps, String id) { - return Objects.requireNonNull(deps.get(id), "'" + id + "' expected to have been found in: " + deps.keySet()); - } - - /** - * Will trigger an activation if the managed service is not yet active. - * - * @param ctx the context that triggered the activation - * @return the result of the activation - */ - protected Optional maybeActivate(ContextualServiceQuery ctx) { - Objects.requireNonNull(ctx); - - try { - T serviceOrProvider = serviceRef.get(); - - if (serviceOrProvider == null - || Phase.ACTIVE != currentActivationPhase()) { - ActivationRequest req = InjectionServices.createActivationRequestDefault(); - ActivationResult res = activate(req); - if (res.failure()) { - if (ctx.expected()) { - throw activationFailed(res); - } - return Optional.empty(); - } - - serviceOrProvider = serviceRef.get(); - } - - if (ctx.expected() - && serviceOrProvider == null) { - throw managedServiceInstanceShouldHaveBeenSetException(); - } - - return Optional.ofNullable(serviceOrProvider); - } catch (ServiceProviderInjectionException ie) { - throw ie; - } catch (Throwable t) { - throw unableToActivate(t); - } - } - - /** - * Called on a successful finish of activation. - * - * @param logEntryAndResult the record holding the result - * @see #onFailedFinish(AbstractServiceProvider.LogEntryAndResult, Throwable, boolean) - */ - protected void onFinished(LogEntryAndResult logEntryAndResult) { - // NOP - } - - /** - * Called during construction phase. - * - * @param logEntryAndResult the record that holds the results - */ - protected void doConstructing(LogEntryAndResult logEntryAndResult) { - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.CONSTRUCTING); - - Map deps = logEntryAndResult.activationResult.resolvedDependencies(); - serviceRef(createServiceProvider(deps)); - - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } - - /** - * Creates the service with the supplied resolved dependencies, key'ed by each injection point id. - * - * @param resolvedDeps the resolved dependencies - * @return the newly created managed service - * @throws ServiceProviderInjectionException since this is a base method for what is expected to be a code-generated derived - * {@link Activator} then this method will throw an exception if the derived class does not - * implement this method as it - * normally should - */ - protected T createServiceProvider(Map resolvedDeps) { - ServiceProviderInjectionException e = - new ServiceProviderInjectionException("Don't know how to create an instance of " + serviceInfo() - + ". Was the Activator generated?", - this); - activationLog().ifPresent(e::activationLog); - throw e; - } - - /** - * Used to control the order of injection. Jsr-330 is particular about this. - * - * @return the order of injection - */ - protected List serviceTypeInjectionOrder() { - return Collections.singletonList(serviceInfo.serviceTypeName()); - } - - /** - * Called during the injection of fields. - * - * @param target the target - * @param deps the dependencies - * @param injections the injections - * @param forServiceType the service type - */ - protected void doInjectingFields(Object target, - Map deps, - Set injections, - TypeName forServiceType) { - // NOP; meant to be overridden - } - - /** - * Called during the injection of methods. - * - * @param target the target - * @param deps the dependencies - * @param injections the injections - * @param forServiceType the service type - */ - protected void doInjectingMethods(Object target, - Map deps, - Set injections, - TypeName forServiceType) { - // NOP; meant to be overridden - } - - /** - * Called during the {@link PostConstructMethod} process. - * - * @param logEntryAndResult the entry holding the result - */ - protected void doPostConstructing(LogEntryAndResult logEntryAndResult) { - Optional postConstruct = postConstructMethod(); - if (postConstruct.isPresent()) { - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.POST_CONSTRUCTING); - postConstruct.get().postConstruct(); - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } else { - startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.POST_CONSTRUCTING); - } - } - - /** - * Called during the {@link PreDestroyMethod} process. - * - * @param logEntryAndResult the entry holding the result - */ - protected void doPreDestroying(LogEntryAndResult logEntryAndResult) { - Optional preDestroyMethod = preDestroyMethod(); - if (preDestroyMethod.isEmpty()) { - startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.PRE_DESTROYING); - } else { - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.PRE_DESTROYING); - preDestroyMethod.get().preDestroy(); - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } - } - - /** - * Called after the {@link PreDestroyMethod} process. - * - * @param logEntryAndResult the entry holding the result - */ - protected void doDestroying(LogEntryAndResult logEntryAndResult) { - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.DESTROYED); - logEntryAndResult.activationResult.wasResolved(false); - logEntryAndResult.activationResult.resolvedDependencies(Map.of()); - serviceRef(null); - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } - - /** - * Creates an injection exception appropriate when there are no matching qualified services for the context provided. - * - * @param ctx the context - * @return the injection exception - */ - protected ServiceProviderInjectionException expectedQualifiedServiceError(ContextualServiceQuery ctx) { - ServiceProviderInjectionException e = new ServiceProviderInjectionException("Expected to return a non-null instance for: " - + ctx.injectionPointInfo() - + "; with criteria matching: " + ctx.serviceInfoCriteria(), this); - activationLog().ifPresent(e::activationLog); - return e; - } - - /** - * Creates a log entry result based upon the target phase provided. - * - * @param targetPhase the target phase - * @return a new log entry and result record - */ - protected LogEntryAndResult createLogEntryAndResult(Phase targetPhase) { - Phase currentPhase = currentActivationPhase(); - ActivationResult.Builder activationResult = ActivationResult.builder() - .serviceProvider(this) - .startingActivationPhase(currentPhase) - .finishingActivationPhase(currentPhase) - .targetActivationPhase(targetPhase); - ActivationLogEntry.Builder logEntry = ActivationLogEntry.builder() - .serviceProvider(this) - .event(Event.STARTING) - .threadId(Thread.currentThread().getId()) - .activationResult(activationResult.build()); - return new LogEntryAndResult(logEntry, activationResult); - } - - /** - * Starts transitioning to a new phase. - * - * @param logEntryAndResult the record that will hold the state of the transition - * @param newPhase the target new phase - */ - protected void startTransitionCurrentActivationPhase(LogEntryAndResult logEntryAndResult, - Phase newPhase) { - Objects.requireNonNull(logEntryAndResult); - Objects.requireNonNull(newPhase); - logEntryAndResult.activationResult - .finishingActivationPhase(newPhase); - this.phase = newPhase; - logEntryAndResult.logEntry - .event(Event.STARTING) - .activationResult(logEntryAndResult.activationResult.build()); - activationLog().ifPresent(log -> log.record(logEntryAndResult.logEntry.build())); - onPhaseEvent(Event.STARTING, this.phase); - } - - Map resolveDependencies(Map mutablePlans) { - Map result = new LinkedHashMap<>(); - - Map.copyOf(mutablePlans).forEach((key, value) -> { - Object resolved; - if (value.wasResolved()) { - resolved = value.resolved(); - result.put(key, resolveOptional(value, resolved)); - } else { - List> serviceProviders = value.injectionPointQualifiedServiceProviders(); - serviceProviders = (serviceProviders == null) - ? List.of() - : Collections.unmodifiableList(serviceProviders); - if (serviceProviders.isEmpty() - && !value.unqualifiedProviders().isEmpty()) { - resolved = List.of(); // deferred - } else { - resolved = DefaultInjectionPlans.resolve(this, value.injectionPointInfo(), serviceProviders, logger()); - } - result.put(key, resolveOptional(value, resolved)); - } - - if (value.resolved().isEmpty()) { - // update the original plans map to properly reflect the resolved value - mutablePlans.put(key, HelidonInjectionPlan.builder(value) - .wasResolved(true) - .update(builder -> { - if (resolved != null) { - builder.resolved(resolved); - } - }) - .build()); - } - }); - - return result; - } - - void serviceRef(T instance) { - serviceRef.set(instance); - } - - void onFailedFinish(LogEntryAndResult logEntryAndResult, - Throwable t, - boolean throwOnError, - Optional log) { - ServiceProviderInjectionException e; - - ActivationLogEntry.Builder res = logEntryAndResult.logEntry; - Throwable prev = res.error().orElse(null); - if (prev == null || !(t instanceof ServiceProviderInjectionException)) { - String msg = (t != null && t.getMessage() != null) ? t.getMessage() : "Failed to complete operation"; - e = new ServiceProviderInjectionException(msg, t, this); - log.ifPresent(e::activationLog); - } else { - e = (ServiceProviderInjectionException) t; - } - - res.error(e); - logEntryAndResult.activationResult.finishingStatus(ActivationStatus.FAILURE); - - if (throwOnError) { - throw e; - } - } - - void startAndFinishTransitionCurrentActivationPhase(LogEntryAndResult logEntryAndResult, - Phase newPhase) { - startTransitionCurrentActivationPhase(logEntryAndResult, newPhase); - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } - - void finishedTransitionCurrentActivationPhase(LogEntryAndResult logEntryAndResult) { - logEntryAndResult.logEntry - .event(Event.FINISHED) - .activationResult(logEntryAndResult.activationResult.build()); - ActivationLog log = activationLog().orElse(null); - if (log != null) { - log.record(logEntryAndResult.logEntry.build()); - } - onPhaseEvent(Event.FINISHED, this.phase); - } - - // if we are here then we are not yet at the ultimate target phase, and we either have to activate or deactivate - private LogEntryAndResult preambleActivate(ActivationRequest req) { - assert (injectionServices != null) : "not initialized"; - - LogEntryAndResult logEntryAndResult = createLogEntryAndResult(req.targetPhase()); - req.injectionPoint().ifPresent(logEntryAndResult.logEntry::injectionPoint); - Phase startingPhase = req.startingPhase().orElse(Phase.PENDING); - startTransitionCurrentActivationPhase(logEntryAndResult, startingPhase); - - // fail fast if we are in a recursive situation on this thread... - if (logEntryAndResult.logEntry.threadId() == lastActivationThreadId && lastActivationThreadId > 0) { - onFailedFinish(logEntryAndResult, recursiveActivationInjectionError(logEntryAndResult.logEntry), req.throwIfError()); - return logEntryAndResult; - } - - InjectionServicesConfig cfg = injectionServices.config(); - boolean didAcquire = false; - try { - // let's wait a bit on the semaphore until we read timeout (probably detecting a deadlock situation) - if (!activationSemaphore.tryAcquire(cfg.activationDeadlockDetectionTimeout().toMillis(), TimeUnit.MILLISECONDS)) { - // if we couldn't get semaphore than we (or someone else) is busy activating this services, or we deadlocked - onFailedFinish(logEntryAndResult, - timedOutActivationInjectionError(logEntryAndResult.logEntry), - req.throwIfError()); - return logEntryAndResult; - } - didAcquire = true; - - // if we made it to here then we "own" the semaphore and the subsequent activation steps... - lastActivationThreadId = Thread.currentThread().getId(); - logEntryAndResult.logEntry.threadId(lastActivationThreadId); - - if (logEntryAndResult.activationResult.build().finished()) { - didAcquire = false; - activationSemaphore.release(); - } - - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } catch (Throwable t) { - this.lastActivationThreadId = 0; - if (didAcquire) { - activationSemaphore.release(); - } - - ServiceProviderInjectionException e = interruptedPreActivationInjectionError(logEntryAndResult.logEntry, t); - onFailedFinish(logEntryAndResult, e, req.throwIfError()); - } - - return logEntryAndResult; - } - - private void onInitialized() { - if (logger().isLoggable(System.Logger.Level.DEBUG)) { - logger().log(System.Logger.Level.DEBUG, this + " initialized."); - } - } - - private void doStartingLifecycle(LogEntryAndResult logEntryAndResult) { - startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVATION_STARTING); - } - - private void doGatheringDependencies(LogEntryAndResult logEntryAndResult) { - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.GATHERING_DEPENDENCIES); - - Map plans = Objects.requireNonNull(getOrCreateInjectionPlan(false)); - Map deps = resolveDependencies(plans); - if (!deps.isEmpty()) { - logEntryAndResult.activationResult.resolvedDependencies(deps); - } - logEntryAndResult.activationResult.injectionPlans(plans); - - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } - - @SuppressWarnings("unchecked") - private Object resolveOptional(HelidonInjectionPlan plan, - Object resolved) { - if (!plan.injectionPointInfo().optionalWrapped() && resolved instanceof Optional) { - return ((Optional) resolved).orElse(null); - } - return resolved; - } - - private void doInjecting(LogEntryAndResult logEntryAndResult) { - if (!ServiceUtils.isQualifiedInjectionTarget(this)) { - startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.INJECTING); - return; - } - - Map deps = logEntryAndResult.activationResult.resolvedDependencies(); - if (deps == null || deps.isEmpty()) { - startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.INJECTING); - return; - } - - startTransitionCurrentActivationPhase(logEntryAndResult, Phase.INJECTING); - - T target = Objects.requireNonNull(serviceRef.get()); - List serviceTypeOrdering = serviceTypeInjectionOrder(); - LinkedHashSet injections = new LinkedHashSet<>(); - serviceTypeOrdering.forEach((forServiceType) -> { - try { - doInjectingFields(target, deps, injections, forServiceType); - doInjectingMethods(target, deps, injections, forServiceType); - } catch (Throwable t) { - throw new ServiceProviderInjectionException("Failed to activate/inject: " + this - + "; dependency map was: " + deps, t, this); - } - }); - - finishedTransitionCurrentActivationPhase(logEntryAndResult); - } - - private void doActivationFinishing(LogEntryAndResult logEntryAndResult) { - startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVATION_FINISHING); - } - - private void doActivationActive(LogEntryAndResult logEntryAndResult) { - startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVE); - } - - private ServiceProviderInjectionException recursiveActivationInjectionError(ActivationLogEntry.Builder entry) { - ServiceProvider targetServiceProvider = entry.serviceProvider().orElseThrow(); - ServiceProviderInjectionException e = - new ServiceProviderInjectionException("A circular dependency found during activation of " + targetServiceProvider, - targetServiceProvider); - activationLog().ifPresent(e::activationLog); - entry.error(e); - return e; - } - - private ServiceProviderInjectionException timedOutActivationInjectionError(ActivationLogEntry.Builder entry) { - ServiceProvider targetServiceProvider = entry.serviceProvider().orElseThrow(); - ServiceProviderInjectionException e = - new ServiceProviderInjectionException("Timed out during activation of " + targetServiceProvider, - targetServiceProvider); - activationLog().ifPresent(e::activationLog); - entry.error(e); - return e; - } - - private ServiceProviderInjectionException timedOutDeActivationInjectionError(ActivationLogEntry.Builder entry) { - ServiceProvider targetServiceProvider = entry.serviceProvider().orElseThrow(); - ServiceProviderInjectionException e = - new ServiceProviderInjectionException("Timed out during deactivation of " + targetServiceProvider, - targetServiceProvider); - activationLog().ifPresent(e::activationLog); - entry.error(e); - return e; - } - - private ServiceProviderInjectionException interruptedPreActivationInjectionError(ActivationLogEntry.Builder entry, - Throwable cause) { - ServiceProvider targetServiceProvider = entry.serviceProvider().orElseThrow(); - ServiceProviderInjectionException e = new ServiceProviderInjectionException( - "A circular dependency found during activation of " + targetServiceProvider, - cause, - targetServiceProvider); - activationLog().ifPresent(e::activationLog); - entry.error(e); - return e; - } - - private ServiceProviderInjectionException managedServiceInstanceShouldHaveBeenSetException() { - ServiceProviderInjectionException e = new ServiceProviderInjectionException( - "This managed service instance expected to have been set", - this); - activationLog().ifPresent(e::activationLog); - return e; - } - - private ServiceProviderInjectionException activationFailed(ActivationResult res) { - ServiceProviderInjectionException e = new ServiceProviderInjectionException("Activation failed: " + res, this); - activationLog().ifPresent(e::activationLog); - return e; - } - - private InjectionServiceProviderException unableToActivate(Throwable cause) { - return new InjectionServiceProviderException("Unable to activate: " + getClass().getName(), cause, this); - } - - private InjectionServiceProviderException alreadyInitialized() { - throw new InjectionServiceProviderException("Already initialized", this); - } - - private void logMultiDefInjectionNote(String id, - Object prev, - InjectionPointInfo ipDep) { - String message = "There are two different services sharing the same injection point id; first = " - + prev + " and the second = " + ipDep + "; both use the id '" + id - + "'; note that the second will override the first"; - if (log != null) { - log.record(ActivationLogEntry.builder() - .serviceProvider(this) - .injectionPoint(ipDep) - .message(message) - .build()); - } else { - logger().log(System.Logger.Level.DEBUG, message); - } - } - - /** - * Represents a result of a phase transition. - * - * @see #createLogEntryAndResult(Phase) - */ - // note that for one result, there may be N logEntry records we will build and write to the log - protected static class LogEntryAndResult /* implements Cloneable*/ { - private final ActivationResult.Builder activationResult; - private final ActivationLogEntry.Builder logEntry; - - LogEntryAndResult(ActivationLogEntry.Builder logEntry, - ActivationResult.Builder activationResult) { - this.logEntry = logEntry; - this.activationResult = activationResult; - } - - ActivationResult.Builder activationResult() { - return activationResult; - } - - ActivationLogEntry.Builder logEntry() { - return logEntry; - } - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/BoundedServiceProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/BoundedServiceProvider.java deleted file mode 100644 index ee700b5c1a9..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/BoundedServiceProvider.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import io.helidon.common.LazyValue; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.DeActivator; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.PostConstructMethod; -import io.helidon.inject.api.PreDestroyMethod; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; - -/** - * A service provider that is bound to a particular injection point context. - * - * @param the type of the bound service provider - */ -class BoundedServiceProvider implements ServiceProvider { - - private final ServiceProvider binding; - private final InjectionPointInfo ipInfoCtx; - private final LazyValue instance; - private final LazyValue> instances; - - private BoundedServiceProvider(ServiceProvider binding, - InjectionPointInfo ipInfoCtx) { - this.binding = Objects.requireNonNull(binding); - this.ipInfoCtx = Objects.requireNonNull(ipInfoCtx); - ContextualServiceQuery query = ContextualServiceQuery.builder() - .injectionPointInfo(ipInfoCtx) - .serviceInfoCriteria(ipInfoCtx.dependencyToServiceInfo()) - .expected(false).build(); - this.instance = LazyValue.create(() -> binding.first(query).orElse(null)); - this.instances = LazyValue.create(() -> binding.list(query)); - } - - /** - * Creates a bound service provider to a specific binding. - * - * @param binding the bound service provider - * @param ipInfoCtx the binding context - * @return the service provider created, wrapping the binding delegate provider - */ - static ServiceProvider create(ServiceProvider binding, - InjectionPointInfo ipInfoCtx) { - assert (binding != null); - assert (!(binding instanceof BoundedServiceProvider)); - if (binding instanceof AbstractServiceProvider) { - AbstractServiceProvider sp = (AbstractServiceProvider) binding; - if (!sp.isProvider()) { - return binding; - } - } - return new BoundedServiceProvider<>(binding, ipInfoCtx); - } - - @Override - public String toString() { - return binding.toString(); - } - - @Override - public int hashCode() { - return binding.hashCode(); - } - - @Override - public boolean equals(Object another) { - return (another instanceof ServiceProvider && binding.equals(another)); - } - - @Override - public Optional first(ContextualServiceQuery query) { - assert (query.injectionPointInfo().isEmpty() || ipInfoCtx.equals(query.injectionPointInfo().get())) - : query.injectionPointInfo() + " was not equal to " + this.ipInfoCtx; - assert (ipInfoCtx.dependencyToServiceInfo().matches(query.serviceInfoCriteria())) - : query.serviceInfoCriteria() + " did not match " + this.ipInfoCtx.dependencyToServiceInfo(); - return Optional.ofNullable(instance.get()); - } - - @Override - public List list(ContextualServiceQuery query) { - assert (query.injectionPointInfo().isEmpty() || ipInfoCtx.equals(query.injectionPointInfo().get())) - : query.injectionPointInfo() + " was not equal to " + this.ipInfoCtx; - assert (ipInfoCtx.dependencyToServiceInfo().matches(query.serviceInfoCriteria())) - : query.serviceInfoCriteria() + " did not match " + this.ipInfoCtx.dependencyToServiceInfo(); - return instances.get(); - } - - @Override - public String id() { - return binding.id(); - } - - @Override - public String description() { - return binding.description(); - } - - @Override - public boolean isProvider() { - return binding.isProvider(); - } - - @Override - public ServiceInfo serviceInfo() { - return binding.serviceInfo(); - } - - @Override - public DependenciesInfo dependencies() { - return binding.dependencies(); - } - - @Override - public Phase currentActivationPhase() { - return binding.currentActivationPhase(); - } - - @Override - public Optional activator() { - return binding.activator(); - } - - @Override - public Optional deActivator() { - return binding.deActivator(); - } - - @Override - public Optional postConstructMethod() { - return binding.postConstructMethod(); - } - - @Override - public Optional preDestroyMethod() { - return binding.preDestroyMethod(); - } - - @Override - public Optional> serviceProviderBindable() { - return Optional.of((ServiceProviderBindable) binding); - } - - @Override - public Class serviceType() { - return binding.serviceType(); - } -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultActivationLog.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultActivationLog.java deleted file mode 100644 index 8717afa5a9a..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultActivationLog.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.lang.System.Logger; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.CopyOnWriteArrayList; - -import io.helidon.inject.api.ActivationLog; -import io.helidon.inject.api.ActivationLogEntry; -import io.helidon.inject.api.ActivationLogQuery; - -/** - * The default reference implementation of {@link ActivationLog} and {@link io.helidon.inject.ActivationLogQuery}. - */ -class DefaultActivationLog implements ActivationLog, ActivationLogQuery { - private final List log; - private final Logger logger; - private Logger.Level level; - - private DefaultActivationLog(List log, - Logger logger, - Logger.Level level) { - this.log = log; - this.logger = logger; - this.level = level; - } - - /** - * Create a retained activation log that tee's to the provided logger. A retained log is capable of supporting - * {@link ActivationLogQuery}. - * - * @param logger the logger to use - * @return the created activity log - */ - static DefaultActivationLog createRetainedLog(Logger logger) { - return new DefaultActivationLog(new CopyOnWriteArrayList<>(), logger, Logger.Level.INFO); - } - - /** - * Create an unretained activation log that simply logs to the provided logger. An unretained log is not capable of - * supporting {@link ActivationLogQuery}. - * - * @param logger the logger to use - * @return the created activity log - */ - static DefaultActivationLog createUnretainedLog(Logger logger) { - return new DefaultActivationLog(null, logger, Logger.Level.DEBUG); - } - - /** - * Sets the logging level. - * - * @param level the level - */ - public void level(Logger.Level level) { - this.level = level; - } - - @Override - public ActivationLogEntry record(ActivationLogEntry entry) { - if (log != null) { - log.add(Objects.requireNonNull(entry)); - } - - if (logger != null) { - logger.log(level, entry); - } - - return entry; - } - - @Override - public Optional toQuery() { - return (log != null) ? Optional.of(this) : Optional.empty(); - } - - @Override - public boolean reset(boolean ignored) { - if (null != log) { - boolean affected = !log.isEmpty(); - log.clear(); - return affected; - } - - return false; - } - - @Override - public List fullActivationLog() { - return (null == log) ? List.of() : List.copyOf(log); - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlanBinder.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlanBinder.java deleted file mode 100644 index faa0d849fc3..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlanBinder.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Optional; - -import io.helidon.inject.api.ServiceInjectionPlanBinder; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; - -class DefaultInjectionPlanBinder implements ServiceInjectionPlanBinder, ServiceInjectionPlanBinder.Binder { - - private final DefaultServices services; - - DefaultInjectionPlanBinder(DefaultServices services) { - this.services = services; - } - - @Override - public Binder bindTo(ServiceProvider untrustedSp) { - // don't trust what we get, but instead lookup the service provider that we carry in our services registry - ServiceProvider serviceProvider = services.serviceProviderFor(untrustedSp.serviceInfo().serviceTypeName()); - Optional> bindable = ServiceBinderDefault.toBindableProvider(serviceProvider); - Optional binder = (bindable.isPresent()) ? bindable.get().injectionPlanBinder() : Optional.empty(); - if (binder.isEmpty()) { - // basically this means this service will not support compile-time injection - DefaultInjectionServices.LOGGER.log(System.Logger.Level.WARNING, - "service provider is not capable of being bound to injection points: " + serviceProvider); - return this; - } else { - if (DefaultInjectionServices.LOGGER.isLoggable(System.Logger.Level.DEBUG)) { - DefaultInjectionServices.LOGGER.log(System.Logger.Level.DEBUG, "binding injection plan to " + binder.get()); - } - } - - return binder.get(); - } - - @Override - public Binder bind(String id, - ServiceProvider serviceProvider) { - // NOP - return this; - } - - @Override - public Binder bindMany(String id, - ServiceProvider... serviceProviders) { - // NOP - return this; - } - - @Override - public Binder bindVoid(String ipIdentity) { - // NOP - return this; - } - - @Override - public Binder resolvedBind(String ipIdentity, - Class serviceType) { - // NOP - return this; - } - - @Override - public void commit() { - // NOP - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlans.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlans.java deleted file mode 100644 index 96f575ec198..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlans.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.DependencyInfo; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesConfig; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; -import io.helidon.inject.api.ServiceProviderInjectionException; -import io.helidon.inject.api.ServiceProviderProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.spi.InjectionResolver; - -class DefaultInjectionPlans { - private static final TypeName INTERCEPTOR = TypeName.create(Interceptor.class); - private static final TypeName IP_PROVIDER = TypeName.create(InjectionPointProvider.class); - private static final TypeName VOID = TypeName.create(Void.class); - - private DefaultInjectionPlans() { - } - - /** - * Converts the inputs to an injection plans for the given service provider. - * - * @param injectionServices injection services - * @param self the reference to the service provider associated with this plan - * @param dependencies the dependencies - * @param resolveIps flag indicating whether injection points should be resolved - * @param logger the logger to use for any logging - * @return the injection plan per element identity belonging to the service provider - */ - static Map createInjectionPlans(InjectionServices injectionServices, - ServiceProvider self, - DependenciesInfo dependencies, - boolean resolveIps, - System.Logger logger) { - Map result = new LinkedHashMap<>(); - if (dependencies.allDependencies().isEmpty()) { - return result; - } - - dependencies.allDependencies() - .forEach(dep -> { - try { - accumulate(dep, result, injectionServices, self, resolveIps, logger); - } catch (Exception e) { - throw new InjectionServiceProviderException("An error occurred creating the injection plan", e, self); - } - }); - - return result; - } - - /** - * Special case where we have qualifiers on the criteria, but we should still allow any - * {@link InjectionPointProvider} match regardless, since it will be the ultimate determining agent - * to use the dependency info - not the services registry default logic. - * - * @param services the services registry - * @param depTo the dependency with the qualifiers - * @return a list of {@link InjectionPointProvider}s that can handle the contracts requested - */ - static List> injectionPointProvidersFor(Services services, - ServiceInfoCriteria depTo) { - if (depTo.qualifiers().isEmpty()) { - return List.of(); - } - - if (depTo.contractsImplemented().isEmpty()) { - return List.of(); - } - - ServiceInfoCriteria modifiedDepTo = ServiceInfoCriteria.builder(depTo) - .qualifiers(Set.of()) - .build(); - - List> providers = services.lookupAll(modifiedDepTo); - return providers.stream() - .filter(it -> it.serviceInfo().contractsImplemented().contains(IP_PROVIDER)) - .toList(); - } - - /** - * Creates and maybe adjusts the criteria to match the context of who is doing the lookup. - * - * @param dep the dependency info to lookup - * @param self the service doing the lookup - * @param selfInfo the service info for the service doing the lookup - * @return the criteria - */ - static ServiceInfoCriteria toCriteria(DependencyInfo dep, - ServiceProvider self, - ServiceInfo selfInfo) { - ServiceInfoCriteria criteria = dep.dependencyTo(); - ServiceInfoCriteria.Builder builder = null; - if (selfInfo.declaredWeight().isPresent() - && selfInfo.contractsImplemented().containsAll(criteria.contractsImplemented())) { - // if we have a weight on ourselves, and we inject an interface that we actually offer, then - // be sure to use it to get lower weighted injection points - builder = ServiceInfoCriteria.builder(criteria) - .weight(selfInfo.declaredWeight().get()); - } - - if ((self instanceof ServiceProviderBindable) && ((ServiceProviderBindable) self).isInterceptor()) { - if (builder == null) { - builder = ServiceInfoCriteria.builder(criteria); - } - builder = builder.includeIntercepted(true); - } - - return (builder != null) ? builder.build() : criteria; - } - - /** - * Resolution comes after the plan was loaded or created. - * - * @param self the reference to the service provider associated with this plan - * @param ipInfo the injection point - * @param serviceProviders the service providers that qualify in preferred weighted order - * @param logger the logger to use for any logging - * @return the resolution (and activation) of the qualified service provider(s) in the form acceptable to the injection point - */ - @SuppressWarnings("unchecked") - static Object resolve(ServiceProvider self, - InjectionPointInfo ipInfo, - List> serviceProviders, - System.Logger logger) { - if (ipInfo.staticDeclaration()) { - throw new ServiceProviderInjectionException(ipInfo + ": static is not supported", null, self); - } - if (ipInfo.access() == AccessModifier.PRIVATE) { - throw new ServiceProviderInjectionException(ipInfo + ": private is not supported", null, self); - } - - try { - if (VOID.equals(ipInfo.serviceTypeName())) { - return null; - } - - if (ipInfo.listWrapped()) { - if (ipInfo.optionalWrapped()) { - throw new ServiceProviderInjectionException("Optional + List injection is not supported for " - + ipInfo.serviceTypeName() + "." + ipInfo.elementName()); - } - - if (serviceProviders.isEmpty()) { - if (!allowNullableInjectionPoint(ipInfo)) { - throw new ServiceProviderInjectionException("Expected to resolve a service appropriate for " - + ipInfo.serviceTypeName() + "." + ipInfo.elementName(), - DefaultServices - .resolutionBasedInjectionError( - ipInfo.dependencyToServiceInfo()), - self); - } else { - return serviceProviders; - } - } - - if (ipInfo.providerWrapped() && !ipInfo.optionalWrapped()) { - return serviceProviders; - } - - if (ipInfo.listWrapped() && !ipInfo.optionalWrapped()) { - return toEligibleInjectionRefs(ipInfo, self, serviceProviders, true); - } - } else if (serviceProviders.isEmpty()) { - if (ipInfo.optionalWrapped()) { - return Optional.empty(); - } else { - throw new ServiceProviderInjectionException("Expected to resolve a service appropriate for " - + ipInfo.serviceTypeName() + "." + ipInfo.elementName(), - DefaultServices.resolutionBasedInjectionError(ipInfo.dependencyToServiceInfo()), - self); - } - } else { - // "standard" case - ServiceProvider serviceProvider = serviceProviders.get(0); - Optional> serviceProviderBindable = - ServiceBinderDefault.toBindableProvider(ServiceBinderDefault.toRootProvider(serviceProvider)); - if (serviceProviderBindable.isPresent() - && serviceProviderBindable.get() != serviceProvider - && serviceProviderBindable.get() instanceof ServiceProviderProvider) { - serviceProvider = serviceProviderBindable.get(); - serviceProviders = (List>) ((ServiceProviderProvider) serviceProvider) - .serviceProviders(ipInfo.dependencyToServiceInfo(), true, false); - if (!serviceProviders.isEmpty()) { - serviceProvider = serviceProviders.get(0); - } - } - - if (ipInfo.providerWrapped()) { - return ipInfo.optionalWrapped() ? Optional.of(serviceProvider) : serviceProvider; - } - - if (ipInfo.optionalWrapped()) { - Optional optVal; - try { - optVal = Objects.requireNonNull( - serviceProvider.first(ContextualServiceQuery.create(ipInfo, false))); - } catch (ServiceProviderInjectionException e) { - logger.log(System.Logger.Level.WARNING, e.getMessage(), e); - optVal = Optional.empty(); - } - return optVal; - } - - ContextualServiceQuery query = ContextualServiceQuery.create(ipInfo, true); - Optional first = serviceProvider.first(query); - return first.orElse(null); - } - } catch (ServiceProviderInjectionException ie) { - throw ie; - } catch (Throwable t) { - throw expectedToResolveCriteria(ipInfo, t, self); - } - - throw expectedToResolveCriteria(ipInfo, null, self); - } - - @SuppressWarnings("unchecked") - private static void accumulate(DependencyInfo dep, - Map result, - InjectionServices injectionServices, - ServiceProvider self, - boolean resolveIps, - System.Logger logger) { - ServiceInfo selfInfo = self.serviceInfo(); - ServiceInfoCriteria depTo = toCriteria(dep, self, selfInfo); - Services services = injectionServices.services(); - InjectionServicesConfig cfg = injectionServices.config(); - boolean isPrivateSupported = cfg.supportsJsr330Privates(); - boolean isStaticSupported = cfg.supportsJsr330Statics(); - - if (self instanceof InjectionResolver) { - dep.injectionPointDependencies() - .stream() - .filter(ipInfo -> (isPrivateSupported || ipInfo.access() != AccessModifier.PRIVATE) - && (isStaticSupported || !ipInfo.staticDeclaration())) - .forEach(ipInfo -> { - String id = ipInfo.id(); - if (!result.containsKey(id)) { - Object resolved = ((InjectionResolver) self) - .resolve(ipInfo, injectionServices, self, resolveIps) - .orElse(null); - Object target = (resolved instanceof Optional) - ? ((Optional) resolved).orElse(null) : resolved; - if (target != null) { - HelidonInjectionPlan.Builder planBuilder = HelidonInjectionPlan.builder() - .serviceProvider(self) - .injectionPointInfo(ipInfo) - .injectionPointQualifiedServiceProviders(toIpQualified(target)) - .unqualifiedProviders(toIpUnqualified(target)) - .wasResolved(resolved != null); - - if (ipInfo.optionalWrapped()) { - planBuilder.resolved((target instanceof Optional && ((Optional) target).isEmpty()) - ? Optional.empty() : Optional.of(target)); - } else { - if (target instanceof Optional) { - target = ((Optional) target).orElse(null); - } - if (target != null) { - planBuilder.resolved(target); - } - } - - HelidonInjectionPlan plan = planBuilder.build(); - Object prev = result.put(id, plan); - assert (prev == null) : ipInfo; - } - } - }); - } - - List> tmpServiceProviders = services.lookupAll(depTo, false); - if (tmpServiceProviders.isEmpty()) { - if (VoidServiceProvider.INSTANCE.serviceInfo().matches(depTo)) { - tmpServiceProviders = VoidServiceProvider.LIST_INSTANCE; - } else { - tmpServiceProviders = injectionPointProvidersFor(services, depTo); - } - } - - // filter down the selections to not include self - List> serviceProviders = - (!tmpServiceProviders.isEmpty()) - ? tmpServiceProviders.stream() - .filter(sp -> !isSelf(self, sp)) - .collect(Collectors.toList()) - : tmpServiceProviders; - - dep.injectionPointDependencies() - .stream() - .filter(ipInfo -> - (isPrivateSupported || ipInfo.access() != AccessModifier.PRIVATE) - && (isStaticSupported || !ipInfo.staticDeclaration())) - .forEach(ipInfo -> { - String id = ipInfo.id(); - if (!result.containsKey(id)) { - Object resolved = (resolveIps) - ? resolve(self, ipInfo, serviceProviders, logger) : null; - if (!resolveIps && !ipInfo.optionalWrapped() - && serviceProviders.isEmpty() - && !allowNullableInjectionPoint(ipInfo)) { - throw DefaultServices.resolutionBasedInjectionError( - ipInfo.dependencyToServiceInfo()); - } - HelidonInjectionPlan plan = HelidonInjectionPlan.builder() - .injectionPointInfo(ipInfo) - .injectionPointQualifiedServiceProviders(serviceProviders) - .serviceProvider(self) - .wasResolved(resolveIps) - .update(builder -> { - if (resolved instanceof Optional opt) { - opt.ifPresent(builder::resolved); - } else { - if (resolved != null) { - builder.resolved(resolved); - } - } - }) - .build(); - Object prev = result.put(id, plan); - assert (prev == null) : ipInfo; - } - }); - } - - private static List> toIpQualified(Object target) { - if (target instanceof Collection) { - List> result = new ArrayList<>(); - ((Collection) target).stream() - .map(DefaultInjectionPlans::toIpQualified) - .forEach(result::addAll); - return result; - } - - return (target instanceof AbstractServiceProvider) - ? List.of((ServiceProvider) target) - : List.of(); - } - - private static List toIpUnqualified(Object target) { - if (target instanceof Collection) { - List result = new ArrayList<>(); - ((Collection) target).stream() - .map(DefaultInjectionPlans::toIpUnqualified) - .forEach(result::addAll); - return result; - } - - return (target == null || target instanceof AbstractServiceProvider) - ? List.of() - : List.of(target); - } - - private static boolean isSelf(ServiceProvider self, - Object other) { - assert (self != null); - - if (self == other) { - return true; - } - - if (self instanceof ServiceProviderBindable) { - Object selfInterceptor = ((ServiceProviderBindable) self).interceptor().orElse(null); - - return other == selfInterceptor; - } - - return false; - } - - private static boolean allowNullableInjectionPoint(InjectionPointInfo ipInfo) { - if (ipInfo.listWrapped()) { - // allow empty lists to be injected - return true; - } - - ServiceInfoCriteria missingServiceInfo = ipInfo.dependencyToServiceInfo(); - Set contractsNeeded = missingServiceInfo.contractsImplemented(); - return (1 == contractsNeeded.size() && contractsNeeded.contains(INTERCEPTOR)); - } - - @SuppressWarnings({"unchecked", "rawTypes"}) - private static List toEligibleInjectionRefs(InjectionPointInfo ipInfo, - ServiceProvider self, - List> list, - boolean expected) { - List result = new ArrayList<>(); - - ContextualServiceQuery query = ContextualServiceQuery.builder() - .injectionPointInfo(ipInfo) - .serviceInfoCriteria(ipInfo.dependencyToServiceInfo()) - .expected(expected) - .build(); - for (ServiceProvider sp : list) { - Collection instances = sp.list(query); - result.addAll(instances); - } - - if (expected && result.isEmpty()) { - throw expectedToResolveCriteria(ipInfo, null, self); - } - - return result; - } - - private static ServiceProviderInjectionException expectedToResolveCriteria(InjectionPointInfo ipInfo, - Throwable cause, - ServiceProvider self) { - String msg = (cause == null) ? "Expected" : "Failed"; - return new ServiceProviderInjectionException(msg + " to resolve a service instance appropriate for '" - + ipInfo.serviceTypeName() + "." + ipInfo.elementName() - + "' with criteria = '" + ipInfo.dependencyToServiceInfo(), - cause, self); - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServices.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServices.java deleted file mode 100644 index c584feb6531..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServices.java +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.stream.Collectors; - -import io.helidon.common.config.Config; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ActivationLog; -import io.helidon.inject.api.ActivationLogEntry; -import io.helidon.inject.api.ActivationLogQuery; -import io.helidon.inject.api.ActivationPhaseReceiver; -import io.helidon.inject.api.ActivationResult; -import io.helidon.inject.api.ActivationStatus; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.CallingContext; -import io.helidon.inject.api.CallingContextFactory; -import io.helidon.inject.api.Event; -import io.helidon.inject.api.InjectionException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesConfig; -import io.helidon.inject.api.Injector; -import io.helidon.inject.api.InjectorOptions; -import io.helidon.inject.api.Metrics; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; - -import static io.helidon.inject.runtime.DefaultInjectionServicesConfig.PROVIDER; - -/** - * The default implementation for {@link InjectionServices}. - */ -class DefaultInjectionServices implements InjectionServices, Resettable { - static final System.Logger LOGGER = System.getLogger(DefaultInjectionServices.class.getName()); - - private final ReentrantReadWriteLock lifecycleLock = new ReentrantReadWriteLock(); - private final AtomicBoolean initializingServicesStarted = new AtomicBoolean(false); - private final AtomicBoolean initializingServicesFinished = new AtomicBoolean(false); - private final AtomicBoolean isBinding = new AtomicBoolean(false); - private final AtomicReference services = new AtomicReference<>(); - private final AtomicReference> moduleList = new AtomicReference<>(); - private final AtomicReference> applicationList = new AtomicReference<>(); - private final Bootstrap bootstrap; - private final InjectionServicesConfig cfg; - private final boolean isGlobal; - private final DefaultActivationLog log; - private final State state = State.create(Phase.INIT); - private CallingContext initializationCallingContext; - - /** - * Constructor taking the bootstrap. - * - * @param bootstrap the bootstrap configuration - * @param global flag indicating whether this is the global con - */ - DefaultInjectionServices(Bootstrap bootstrap, - boolean global) { - this.bootstrap = bootstrap; - this.cfg = InjectionServicesConfig.builder() - .providerName(PROVIDER) - .providerVersion(Versions.CURRENT_INJECT_VERSION) - .config(bootstrap.config().orElseGet(Config::empty) - .get("inject")) - .build(); - this.isGlobal = global; - this.log = cfg.activationLogs() - ? DefaultActivationLog.createRetainedLog(LOGGER) - : DefaultActivationLog.createUnretainedLog(LOGGER); - } - - @Override - public Bootstrap bootstrap() { - return bootstrap; - } - - @Override - public InjectionServicesConfig config() { - return cfg; - } - - @Override - public Optional activationLog() { - return Optional.of(log); - } - - @Override - public Optional injector() { - return Optional.of(new DefaultInjector()); - } - - @Override - public Optional metrics() { - DefaultServices thisServices = services.get(); - if (thisServices == null) { - // never has been any lookup yet - return Optional.of(Metrics.builder().build()); - } - return Optional.of(thisServices.metrics()); - } - - @Override - public Optional> lookups() { - if (!cfg.serviceLookupCaching()) { - return Optional.empty(); - } - - DefaultServices thisServices = services.get(); - if (thisServices == null) { - // never has been any lookup yet - return Optional.of(Set.of()); - } - return Optional.of(thisServices.cache().keySet()); - } - - @Override - public Optional services(boolean initialize) { - boolean isWriteLock = initialize; - Lock lock = (isWriteLock) ? lifecycleLock.writeLock() : lifecycleLock.readLock(); - lock.lock(); - try { - if (!initialize) { - return Optional.ofNullable(services.get()); - } - - init(); - - DefaultServices thisServices = services.get(); - if (thisServices == null) { - lock.unlock(); - lock = lifecycleLock.writeLock(); - lock.lock(); - reset(true); - init(); - thisServices = services.get(); - - if (thisServices == null) { - throw new InjectionException("Unable to reset() after shutdown()"); - } - } - return Optional.of(thisServices); - } finally { - lock.unlock(); - } - } - - @Override - public Optional> shutdown() { - Map result = Map.of(); - DefaultServices current = services.get(); - if (services.compareAndSet(current, null) && current != null) { - State currentState = state.clone().currentPhase(Phase.PRE_DESTROYING); - log("Started shutdown"); - result = doShutdown(current, currentState); - log("Finished shutdown"); - } - return Optional.ofNullable(result); - } - - @Override - // note that this is typically only called during testing, and also in the injection maven-plugin - public boolean reset(boolean deep) { - Lock lock = lifecycleLock.writeLock(); - lock.lock(); - try { - assertNotInitializing(); - if (isInitializing() || isInitialized()) { - // we allow dynamic updates leading up to initialization - after that it should be prevented if not configured on - DefaultServices.assertPermitsDynamic(cfg); - } - boolean result = deep; - - DefaultServices prev = services.get(); - if (prev != null) { - boolean affected = prev.reset(deep); - result |= affected; - } - - boolean affected = log.reset(deep); - result |= affected; - - if (deep) { - isBinding.set(false); - moduleList.set(null); - applicationList.set(null); - if (prev != null) { - services.set(new DefaultServices(cfg)); - } - state.reset(true); - initializingServicesStarted.set(false); - initializingServicesFinished.set(false); - initializationCallingContext = null; - } - - return result; - } catch (Exception e) { - throw new InjectionException("Failed to reset (state=" + state - + ", isInitialized=" + isInitialized() - + ", isInitializing=" + isInitializing() + ")", e); - } finally { - lock.unlock(); - } - } - - /** - * Returns true if Injection is in the midst of initialization. - * - * @return true if initialization is underway - */ - public boolean isInitializing() { - return initializingServicesStarted.get() && !initializingServicesFinished.get(); - } - - /** - * Returns true if Injection was initialized. - * - * @return true if already initialized - */ - public boolean isInitialized() { - return initializingServicesStarted.get() && initializingServicesFinished.get(); - } - - private Map doShutdown(DefaultServices services, - State state) { - long start = System.currentTimeMillis(); - - ThreadFactory threadFactory = r -> { - Thread thread = new Thread(r); - thread.setDaemon(false); - thread.setPriority(Thread.MAX_PRIORITY); - thread.setName("injection-shutdown-" + System.currentTimeMillis()); - return thread; - }; - - Shutdown shutdown = new Shutdown(services, state); - - long finish; - try (ExecutorService es = Executors.newSingleThreadExecutor(threadFactory)) { - return es.submit(shutdown) - .get(cfg.shutdownTimeout().toMillis(), TimeUnit.MILLISECONDS); - } catch (Throwable t) { - finish = System.currentTimeMillis(); - errorLog("Error detected during shutdown (elapsed = " + (finish - start) + " ms)", t); - throw new InjectionException("Error detected during shutdown", t); - } finally { - state.finished(true); - finish = System.currentTimeMillis(); - log("Finished shutdown (elapsed = " + (finish - start) + " ms)"); - } - } - - private void assertNotInitializing() { - if (isBinding.get() || isInitializing()) { - CallingContext initializationCallingContext = this.initializationCallingContext; - String desc = "Calling reset() during the initialization sequence is not supported (binding=" - + isBinding + ", initializingServicesFinished=" - + initializingServicesFinished + ")"; - String msg = (initializationCallingContext == null) - ? InjectionExceptions.toErrorMessage(desc) - : InjectionExceptions.toErrorMessage(initializationCallingContext, desc); - throw new InjectionException(msg); - } - } - - private void init() { - if (!initializingServicesStarted.getAndSet(true)) { - try { - initializeServices(); - } catch (Throwable t) { - state.lastError(t); - initializingServicesStarted.set(false); - if (t instanceof InjectionException) { - throw (InjectionException) t; - } else { - throw new InjectionException("Failed to initialize: " + t.getMessage(), t); - } - } finally { - state.finished(true); - initializingServicesFinished.set(true); - } - } - } - - private void initializeServices() { - initializationCallingContext = CallingContextFactory.create(false).orElse(null); - - if (services.get() == null) { - services.set(new DefaultServices(cfg)); - } - - DefaultServices thisServices = services.get(); - thisServices.state(state); - state.currentPhase(Phase.ACTIVATION_STARTING); - - if (isGlobal) { - // iterate over all modules, binding to each one's set of services, but with NO activations - List modules = findModules(); - try { - isBinding.set(true); - bindModules(thisServices, modules); - } finally { - isBinding.set(false); - } - } - - state.currentPhase(Phase.GATHERING_DEPENDENCIES); - - if (isGlobal) { - // look for the literal injection plan - // typically only be one Application in non-testing runtimes - List apps = findApplications(); - bindApplications(thisServices, apps); - } - - state.currentPhase(Phase.POST_BIND_ALL_MODULES); - - if (isGlobal) { - // only the global services registry gets eventing (no particular reason though) - thisServices.allServiceProviders(false).stream() - .filter(sp -> sp instanceof ActivationPhaseReceiver) - .map(sp -> (ActivationPhaseReceiver) sp) - .forEach(sp -> sp.onPhaseEvent(Event.STARTING, Phase.POST_BIND_ALL_MODULES)); - } - - state.currentPhase(Phase.FINAL_RESOLVE); - - if (isGlobal || cfg.supportsCompileTime()) { - thisServices.allServiceProviders(false).stream() - .filter(sp -> sp instanceof ActivationPhaseReceiver) - .map(sp -> (ActivationPhaseReceiver) sp) - .forEach(sp -> sp.onPhaseEvent(Event.STARTING, Phase.FINAL_RESOLVE)); - } - - state.currentPhase(Phase.SERVICES_READY); - - // notify interested service providers of "readiness"... - thisServices.allServiceProviders(false).stream() - .filter(sp -> sp instanceof ActivationPhaseReceiver) - .map(sp -> (ActivationPhaseReceiver) sp) - .forEach(sp -> sp.onPhaseEvent(Event.STARTING, Phase.SERVICES_READY)); - - state.finished(true); - } - - private List findApplications() { - List result = applicationList.get(); - if (result != null) { - return result; - } - - result = new ArrayList<>(); - ServiceLoader serviceLoader = ServiceLoader.load(Application.class); - for (Application app : serviceLoader) { - result.add(app); - } - - if (!cfg.permitsDynamic()) { - applicationList.compareAndSet(null, List.copyOf(result)); - result = applicationList.get(); - } - return result; - } - - private List findModules() { - List result = moduleList.get(); - if (result != null) { - return result; - } - - result = new ArrayList<>(); - ServiceLoader serviceLoader = ServiceLoader.load(ModuleComponent.class); - for (ModuleComponent module : serviceLoader) { - result.add(module); - } - - if (!cfg.permitsDynamic()) { - moduleList.compareAndSet(null, List.copyOf(result)); - result = moduleList.get(); - } - return result; - } - - private void bindApplications(DefaultServices services, - Collection apps) { - if (!cfg.usesCompileTimeApplications()) { - LOGGER.log(System.Logger.Level.DEBUG, "Application binding is disabled"); - return; - } - - if (apps.size() > 1) { - LOGGER.log(System.Logger.Level.INFO, - "There is typically only 1 application instance; app instances = " + apps); - } else if (apps.isEmpty()) { - LOGGER.log(System.Logger.Level.TRACE, "no " + Application.class.getName() + " was found."); - return; - } - - DefaultInjectionPlanBinder injectionPlanBinder = new DefaultInjectionPlanBinder(services); - apps.forEach(app -> services.bind(this, injectionPlanBinder, app)); - } - - private void bindModules(DefaultServices services, - Collection modules) { - if (!cfg.usesCompileTimeModules()) { - LOGGER.log(System.Logger.Level.DEBUG, "Module binding is disabled"); - return; - } - - if (modules.isEmpty()) { - LOGGER.log(System.Logger.Level.WARNING, "No " + ModuleComponent.class.getName() + " was found."); - } else { - modules.forEach(module -> services.bind(this, module, isBinding.get())); - } - } - - private void log(String message) { - ActivationLogEntry entry = ActivationLogEntry.builder() - .message(message) - .build(); - log.record(entry); - } - - private void errorLog(String message, - Throwable t) { - ActivationLogEntry entry = ActivationLogEntry.builder() - .message(message) - .error(t) - .build(); - log.record(entry); - } - - /** - * Will attempt to shut down in reverse order of activation, but only if activation logs are retained. - */ - private class Shutdown implements Callable> { - private final DefaultServices services; - private final State state; - private final ActivationLog log; - private final Injector injector; - private final InjectorOptions opts = InjectorOptions.builder().build(); - private final Map map = new LinkedHashMap<>(); - - Shutdown(DefaultServices services, - State state) { - this.services = Objects.requireNonNull(services); - this.state = Objects.requireNonNull(state); - this.injector = injector().orElseThrow(); - this.log = activationLog().orElseThrow(); - } - - @Override - public Map call() { - Lock lock = lifecycleLock.writeLock(); - lock.lock(); - try { - return doShutdown(); - } finally { - lock.unlock(); - } - } - - private Map doShutdown() { - state.currentPhase(Phase.DESTROYED); - - ActivationLogQuery query = log.toQuery().orElse(null); - if (query != null) { - // we can lean on the log entries in order to shut down in reverse chronological order - List fullyActivationLog = new ArrayList<>(query.fullActivationLog()); - if (!fullyActivationLog.isEmpty()) { - LinkedHashSet> serviceProviderActivations = new LinkedHashSet<>(); - - Collections.reverse(fullyActivationLog); - fullyActivationLog.stream() - .map(ActivationLogEntry::serviceProvider) - .filter(Optional::isPresent) - .map(Optional::get) - .forEach(serviceProviderActivations::add); - - // prepare for the shutdown log event sequence - log.toQuery().ifPresent(it -> it.reset(false)); - - // shutdown using the reverse chronological ordering in the log for starters - doFinalShutdown(serviceProviderActivations); - } - } - - // next get all services that are beyond INIT state, and sort by runlevel order, and shut those down also - List> serviceProviders = services.lookupAll(ServiceInfoCriteria.builder().build(), false); - serviceProviders = serviceProviders.stream() - .filter(sp -> sp.currentActivationPhase().eligibleForDeactivation()) - .collect(Collectors.toList()); - serviceProviders.sort((o1, o2) -> { - int runLevel1 = o1.serviceInfo().realizedRunLevel(); - int runLevel2 = o2.serviceInfo().realizedRunLevel(); - return Integer.compare(runLevel1, runLevel2); - }); - doFinalShutdown(serviceProviders); - - // finally, clear everything - reset(true); - - return map; - } - - private void doFinalShutdown(Collection> serviceProviders) { - for (ServiceProvider csp : serviceProviders) { - Phase startingActivationPhase = csp.currentActivationPhase(); - ActivationResult result; - try { - result = injector.deactivate(csp, opts); - } catch (Throwable t) { - errorLog("error during shutdown", t); - result = ActivationResult.builder() - .serviceProvider(csp) - .startingActivationPhase(startingActivationPhase) - .targetActivationPhase(Phase.DESTROYED) - .finishingActivationPhase(csp.currentActivationPhase()) - .finishingStatus(ActivationStatus.FAILURE) - .error(t) - .build(); - } - map.put(csp.serviceInfo().serviceTypeName(), result); - } - } - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServicesConfig.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServicesConfig.java deleted file mode 100644 index fc61b44380f..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServicesConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServicesConfig; - -/** - * The default reference implementation {@link InjectionServicesConfig}. - *

- * It is strongly suggested that any {@link Bootstrap} configuration is established prior to initializing - * this instance, since the results will vary once any bootstrap configuration is globally set. - */ -class DefaultInjectionServicesConfig { - - static final String PROVIDER = "oracle"; - - private DefaultInjectionServicesConfig() { - } - - static InjectionServicesConfig.Builder createDefaultConfigBuilder() { - return InjectionServicesConfig.builder() - .providerName(PROVIDER) - .providerVersion(Versions.CURRENT_INJECT_VERSION); - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServicesProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServicesProvider.java deleted file mode 100644 index d54b2f5f79c..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionServicesProvider.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.common.Weight; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.spi.InjectionServicesProvider; - -import jakarta.inject.Singleton; - -import static io.helidon.inject.api.ServiceInfoBasics.DEFAULT_INJECT_WEIGHT; - -/** - * The default implementation for {@link InjectionServicesProvider}. - * The first instance created (or first after calling deep {@link #reset}) will be the global services instance. The global - * instance will track the set of loaded modules and applications that are loaded by this JVM. - * - * @see InjectionServices#injectionServices() - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Singleton -@Weight(DEFAULT_INJECT_WEIGHT) -public class DefaultInjectionServicesProvider implements InjectionServicesProvider, Resettable { - private static final AtomicReference INSTANCE = new AtomicReference<>(); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public DefaultInjectionServicesProvider() { - } - - @Override - public InjectionServices services(Bootstrap bootstrap) { - Objects.requireNonNull(bootstrap); - if (INSTANCE.get() == null) { - DefaultInjectionServices global = new DefaultInjectionServices(bootstrap, true); - INSTANCE.compareAndSet(null, global); - } - - if (INSTANCE.get().bootstrap().equals(bootstrap)) { - // the global one - return INSTANCE.get(); - } - - // not the global one - return new DefaultInjectionServices(bootstrap, false); - } - - @Override - public boolean reset(boolean deep) { - DefaultInjectionServices services = INSTANCE.get(); - boolean result = (services != null); - if (services != null) { - services.reset(deep); - if (deep) { - INSTANCE.set(null); - } - } - return result; - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjector.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjector.java deleted file mode 100644 index fcf550582c2..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjector.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Objects; - -import io.helidon.inject.api.ActivationResult; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.DeActivationRequest; -import io.helidon.inject.api.DeActivator; -import io.helidon.inject.api.InjectionException; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.Injector; -import io.helidon.inject.api.InjectorOptions; -import io.helidon.inject.api.ServiceProvider; - -/** - * Default reference implementation for the {@link Injector}. - */ -class DefaultInjector implements Injector { - - @Override - @SuppressWarnings("unchecked") - public ActivationResult activateInject(T serviceOrServiceProvider, - InjectorOptions opts) throws InjectionServiceProviderException { - Objects.requireNonNull(serviceOrServiceProvider); - Objects.requireNonNull(opts); - - ActivationResult.Builder resultBuilder = ActivationResult.builder(); - - if (opts.strategy() != Strategy.ANY && opts.strategy() != Strategy.ACTIVATOR) { - return handleError(resultBuilder, opts, "only " + Strategy.ACTIVATOR + " strategy is supported", null); - } - - if (!(serviceOrServiceProvider instanceof AbstractServiceProvider)) { - return handleError(resultBuilder, opts, "unsupported service type: " + serviceOrServiceProvider, null); - } - - AbstractServiceProvider instance = (AbstractServiceProvider) serviceOrServiceProvider; - resultBuilder.serviceProvider(instance); - - Activator activator = instance.activator().orElse(null); - if (activator == null) { - return handleError(resultBuilder, opts, "the service provider does not have an activator", instance); - } - - return activator.activate(opts.activationRequest()); - } - - @Override - @SuppressWarnings("unchecked") - public ActivationResult deactivate(T serviceOrServiceProvider, - InjectorOptions opts) throws InjectionServiceProviderException { - Objects.requireNonNull(serviceOrServiceProvider); - Objects.requireNonNull(opts); - - ActivationResult.Builder resultBuilder = ActivationResult.builder(); - - if (opts.strategy() != Strategy.ANY && opts.strategy() != Strategy.ACTIVATOR) { - return handleError(resultBuilder, opts, "only " + Strategy.ACTIVATOR + " strategy is supported", null); - } - - if (!(serviceOrServiceProvider instanceof AbstractServiceProvider)) { - return handleError(resultBuilder, opts, "unsupported service type: " + serviceOrServiceProvider, null); - } - - AbstractServiceProvider instance = (AbstractServiceProvider) serviceOrServiceProvider; - resultBuilder.serviceProvider(instance); - - DeActivator deactivator = instance.deActivator().orElse(null); - if (deactivator == null) { - return handleError(resultBuilder, opts, "the service provider does not have a deactivator", instance); - } - - DeActivationRequest request = DeActivationRequest.builder() - .throwIfError(opts.activationRequest().throwIfError()) - .build(); - return deactivator.deactivate(request); - } - - private ActivationResult handleError(ActivationResult.Builder resultBuilder, - InjectorOptions opts, - String message, - ServiceProvider serviceProvider) { - InjectionException e = (serviceProvider == null) - ? new InjectionException(message) : new InjectionServiceProviderException(message, serviceProvider); - resultBuilder.error(e); - if (opts.activationRequest().throwIfError()) { - throw e; - } - return resultBuilder.build(); - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultServices.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultServices.java deleted file mode 100644 index 944f15b1ac5..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultServices.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.CallingContext; -import io.helidon.inject.api.CallingContextFactory; -import io.helidon.inject.api.InjectionException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesConfig; -import io.helidon.inject.api.Intercepted; -import io.helidon.inject.api.Metrics; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.api.ServiceBinder; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; -import io.helidon.inject.api.ServiceProviderInjectionException; -import io.helidon.inject.api.ServiceProviderProvider; -import io.helidon.inject.api.Services; - -import jakarta.inject.Provider; - -/** - * The default reference implementation of {@link Services}. - */ -class DefaultServices implements Services, ServiceBinder, Resettable { - private static final ServiceProviderComparator COMPARATOR = ServiceProviderComparator.create(); - - private final ConcurrentHashMap> servicesByTypeName = new ConcurrentHashMap<>(); - private final ConcurrentHashMap>> servicesByContract = new ConcurrentHashMap<>(); - private final Map>> cache = new ConcurrentHashMap<>(); - private final InjectionServicesConfig cfg; - private final AtomicInteger lookupCount = new AtomicInteger(); - private final AtomicInteger cacheLookupCount = new AtomicInteger(); - private final AtomicInteger cacheHitCount = new AtomicInteger(); - private volatile State stateWatchOnly; // we are watching and not mutating this state - owned by DefaultInjectionServices - - /** - * The constructor taking a configuration. - * - * @param cfg the config - */ - DefaultServices(InjectionServicesConfig cfg) { - this.cfg = Objects.requireNonNull(cfg); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - static List explodeFilterAndSort(Collection coll, - ServiceInfoCriteria criteria, - boolean expected) { - List exploded; - if ((coll.size() > 1) - || coll.stream().anyMatch(sp -> sp instanceof ServiceProviderProvider)) { - exploded = new ArrayList<>(); - - coll.forEach(s -> { - if (s instanceof ServiceProviderProvider) { - List> subList = ((ServiceProviderProvider) s) - .serviceProviders(criteria, true, true); - if (subList != null && !subList.isEmpty()) { - subList.stream().filter(Objects::nonNull).forEach(exploded::add); - } - } else { - exploded.add(s); - } - }); - } else { - exploded = (coll instanceof List) ? (List) coll : new ArrayList<>(coll); - } - - List result; - if (criteria.includeIntercepted()) { - result = exploded; - } else { - result = (List) exploded.stream() - .filter(sp -> !(sp instanceof AbstractServiceProvider) || !((AbstractServiceProvider) sp).isIntercepted()) - .collect(Collectors.toList()); - } - - if (expected && result.isEmpty()) { - throw resolutionBasedInjectionError(criteria); - } - - if (result.size() > 1) { - result.sort(serviceProviderComparator()); - } - - return result; - } - - static boolean hasContracts(ServiceInfoCriteria criteria) { - return !criteria.contractsImplemented().isEmpty(); - } - - static boolean isIntercepted(ServiceProvider sp) { - return (sp instanceof ServiceProviderBindable && ((ServiceProviderBindable) sp).isIntercepted()); - } - - /** - * First use weight, then use FQN of the service type name as the secondary comparator if weights are the same. - * - * @return the comparator - * @see ServiceProviderComparator - */ - static Comparator> serviceProviderComparator() { - return COMPARATOR; - } - - static void assertPermitsDynamic(InjectionServicesConfig cfg) { - if (!cfg.permitsDynamic()) { - String desc = "Services are configured to prevent dynamic updates.\n" - + "Set config 'inject.permits-dynamic = true' to enable"; - Optional callCtx = CallingContextFactory.create(false); - String msg = callCtx.map(callingContext -> InjectionExceptions.toErrorMessage(callingContext, desc)) - .orElseGet(() -> InjectionExceptions.toErrorMessage(desc)); - throw new IllegalStateException(msg); - } - } - - static ServiceInfo toValidatedServiceInfo(ServiceProvider serviceProvider) { - ServiceInfo info = serviceProvider.serviceInfo(); - Objects.requireNonNull(info.serviceTypeName(), () -> "service type name is required for " + serviceProvider); - return info; - } - - static ServiceProviderInjectionException serviceProviderAlreadyBoundInjectionError(ServiceProvider previous, - ServiceProvider sp) { - return new ServiceProviderInjectionException("Service provider already bound to " + previous, null, sp); - } - - static ServiceProviderInjectionException resolutionBasedInjectionError(ServiceInfoCriteria ctx) { - return new ServiceProviderInjectionException("Expected to resolve a service matching " + ctx); - } - - static ServiceProviderInjectionException resolutionBasedInjectionError(TypeName serviceTypeName) { - return resolutionBasedInjectionError(ServiceInfoCriteria.builder().serviceTypeName(serviceTypeName).build()); - } - - /** - * Total size of the service registry. - * - * @return total size of the service registry - */ - public int size() { - return servicesByTypeName.size(); - } - - /** - * Performs a reset. When deep is false this will only clear the cache and metrics count. When deep is true will also - * deeply reset each service in the registry as well as clear out the registry. Dynamic must be permitted in config for - * reset to occur. - * - * @param deep set to true will iterate through every service in the registry to attempt a reset on each service as well - * @return true if reset had any affect - * @throws java.lang.IllegalStateException when dynamic is not permitted - */ - @Override - public boolean reset(boolean deep) { - if (Phase.ACTIVATION_STARTING != currentPhase()) { - assertPermitsDynamic(cfg); - } - - boolean changed = (deep || !servicesByTypeName.isEmpty() || lookupCount.get() > 0 || cacheLookupCount.get() > 0); - - if (deep) { - servicesByTypeName.values().forEach(sp -> { - if (sp instanceof Resettable) { - ((Resettable) sp).reset(true); - } - }); - servicesByTypeName.clear(); - servicesByContract.clear(); - } - - clearCacheAndMetrics(); - - return changed; - } - - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - public Optional> lookupFirst(Class type, - boolean expected) { - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addContractImplemented(TypeName.create(type)) - .build(); - return (Optional) lookupFirst(criteria, expected); - } - - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - public Optional> lookupFirst(Class type, - String name, - boolean expected) { - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addContractImplemented(TypeName.create(type)) - .addQualifier(Qualifier.createNamed(name)) - .build(); - return (Optional) lookupFirst(criteria, expected); - } - - @Override - public Optional> lookupFirst(ServiceInfoCriteria criteria, - boolean expected) { - List> result = lookup(criteria, expected, 1); - assert (!expected || !result.isEmpty()); - return (result.isEmpty()) ? Optional.empty() : Optional.of(result.get(0)); - } - - @Override - @SuppressWarnings({"unchecked", "rawtypes"}) - public List> lookupAll(Class type) { - ServiceInfoCriteria serviceInfo = ServiceInfoCriteria.builder() - .addContractImplemented(TypeName.create(type)) - .build(); - return (List) lookup(serviceInfo, false, Integer.MAX_VALUE); - } - - @Override - public List> lookupAll(ServiceInfoCriteria criteria, - boolean expected) { - List> result = lookup(criteria, expected, Integer.MAX_VALUE); - assert (!expected || !result.isEmpty()); - return result; - } - - @Override - public void bind(ServiceProvider serviceProvider) { - if (currentPhase().ordinal() > Phase.GATHERING_DEPENDENCIES.ordinal()) { - assertPermitsDynamic(cfg); - } - - ServiceInfo serviceInfo = toValidatedServiceInfo(serviceProvider); - TypeName serviceTypeName = serviceInfo.serviceTypeName(); - - ServiceProvider previous = servicesByTypeName.putIfAbsent(serviceTypeName, serviceProvider); - if (previous != null && previous != serviceProvider) { - if (cfg.permitsDynamic()) { - DefaultInjectionServices.LOGGER.log(System.Logger.Level.WARNING, - "overwriting " + previous + " with " + serviceProvider); - servicesByTypeName.put(serviceTypeName, serviceProvider); - } else { - throw serviceProviderAlreadyBoundInjectionError(previous, serviceProvider); - } - } - - // special handling in case we are an interceptor... - Set qualifiers = serviceInfo.qualifiers(); - Optional interceptedQualifier = qualifiers.stream() - .filter(q -> q.typeName().name().equals(Intercepted.class.getName())) - .findFirst(); - if (interceptedQualifier.isPresent()) { - // assumption: expected that the root service provider is registered prior to any interceptors - TypeName interceptedServiceTypeName = Objects.requireNonNull(interceptedQualifier.get().value() - .map(TypeName::create) - .orElseThrow()); - ServiceProvider interceptedSp = lookupFirst(ServiceInfoCriteria.builder() - .serviceTypeName(interceptedServiceTypeName) - .build(), true).orElse(null); - if (interceptedSp instanceof ServiceProviderBindable) { - ((ServiceProviderBindable) interceptedSp).interceptor(serviceProvider); - } - } - - boolean added = servicesByContract.computeIfAbsent(serviceTypeName, it -> new TreeSet<>(serviceProviderComparator())) - .add(serviceProvider); - assert (added) : "expected to have added: " + serviceProvider; - - for (TypeName cn : serviceInfo.contractsImplemented()) { - servicesByContract.compute(cn, (contract, servicesSharingThisContract) -> { - if (servicesSharingThisContract == null) { - servicesSharingThisContract = new TreeSet<>(serviceProviderComparator()); - } - boolean ignored = servicesSharingThisContract.add(serviceProvider); - return servicesSharingThisContract; - }); - } - } - - void state(State state) { - this.stateWatchOnly = Objects.requireNonNull(state); - } - - Phase currentPhase() { - return (stateWatchOnly == null) ? Phase.INIT : stateWatchOnly.currentPhase(); - } - - Map>> cache() { - return Map.copyOf(cache); - } - - /** - * Clear the cache and metrics. - */ - void clearCacheAndMetrics() { - cache.clear(); - lookupCount.set(0); - cacheLookupCount.set(0); - cacheHitCount.set(0); - } - - Metrics metrics() { - return Metrics.builder() - .serviceCount(size()) - .lookupCount(lookupCount.get()) - .cacheLookupCount(cacheLookupCount.get()) - .cacheHitCount(cacheHitCount.get()) - .build(); - } - - @SuppressWarnings({"rawtypes"}) - List> lookup(ServiceInfoCriteria criteria, - boolean expected, - int limit) { - List> result; - - lookupCount.incrementAndGet(); - - if (hasContracts(criteria)) { - TypeName serviceTypeName = criteria.serviceTypeName().orElse(null); - boolean hasOneContractInCriteria = (1 == criteria.contractsImplemented().size()); - TypeName theOnlyContractRequested = (hasOneContractInCriteria) - ? criteria.contractsImplemented().iterator().next() : null; - if (serviceTypeName == null - && hasOneContractInCriteria - && criteria.qualifiers().isEmpty()) { - serviceTypeName = theOnlyContractRequested; - } - if (serviceTypeName != null) { - ServiceProvider exact = servicesByTypeName.get(serviceTypeName); - if (exact != null && !isIntercepted(exact)) { - return explodeFilterAndSort(List.of(exact), criteria, expected); - } - } - if (hasOneContractInCriteria) { - Set> subsetOfMatches = servicesByContract.get(theOnlyContractRequested); - if (subsetOfMatches != null) { - result = subsetOfMatches.stream().parallel() - .filter(sp -> sp.serviceInfo().matches(criteria)) - .limit(limit) - .collect(Collectors.toList()); - if (!result.isEmpty()) { - return explodeFilterAndSort(result, criteria, expected); - } - } - } - } - - if (cfg.serviceLookupCaching()) { - result = cache.get(criteria); - cacheLookupCount.incrementAndGet(); - if (result != null) { - cacheHitCount.incrementAndGet(); - return result; - } - } - - // table scan :-( - result = servicesByTypeName.values() - .stream().parallel() - .filter(sp -> sp.serviceInfo().matches(criteria)) - .limit(limit) - .toList(); - if (expected && result.isEmpty()) { - throw resolutionBasedInjectionError(criteria); - } - - if (!result.isEmpty()) { - result = explodeFilterAndSort(result, criteria, expected); - } - - if (cfg.serviceLookupCaching()) { - cache.put(criteria, List.copyOf(result)); - } - - return result; - } - - ServiceProvider serviceProviderFor(TypeName serviceTypeName) { - ServiceProvider serviceProvider = servicesByTypeName.get(serviceTypeName); - if (serviceProvider == null) { - throw resolutionBasedInjectionError(serviceTypeName); - } - return serviceProvider; - } - - List> allServiceProviders(boolean explode) { - if (explode) { - return explodeFilterAndSort(servicesByTypeName.values(), InjectionServices.EMPTY_CRITERIA, false); - } - - return new ArrayList<>(servicesByTypeName.values()); - } - - ServiceBinder createServiceBinder(InjectionServices injectionServices, - DefaultServices services, - String moduleName, - boolean trusted) { - assert (injectionServices.services() == services); - return ServiceBinderDefault.create(injectionServices, moduleName, trusted); - } - - void bind(InjectionServices injectionServices, - DefaultInjectionPlanBinder binder, - Application app) { - String appName = app.named().orElse(app.getClass().getName()); - boolean isLoggable = DefaultInjectionServices.LOGGER.isLoggable(System.Logger.Level.DEBUG); - if (isLoggable) { - DefaultInjectionServices.LOGGER.log(System.Logger.Level.DEBUG, "Starting binding application: " + appName); - } - try { - app.configure(binder); - bind(createServiceProvider(app, injectionServices)); - if (isLoggable) { - DefaultInjectionServices.LOGGER.log(System.Logger.Level.DEBUG, "Finished binding application: " + appName); - } - } catch (Exception e) { - throw new InjectionException("Failed to process: " + app, e); - } - } - - void bind(InjectionServices injectionServices, - ModuleComponent module, - boolean initializing) { - String moduleName = module.named().orElse(module.getClass().getName()); - boolean isLoggable = DefaultInjectionServices.LOGGER.isLoggable(System.Logger.Level.TRACE); - if (isLoggable) { - DefaultInjectionServices.LOGGER.log(System.Logger.Level.TRACE, "starting binding module: " + moduleName); - } - ServiceBinder moduleServiceBinder = createServiceBinder(injectionServices, this, moduleName, initializing); - module.configure(moduleServiceBinder); - bind(createServiceProvider(module, moduleName, injectionServices)); - if (isLoggable) { - DefaultInjectionServices.LOGGER.log(System.Logger.Level.TRACE, "finished binding module: " + moduleName); - } - } - - private ServiceProvider createServiceProvider(ModuleComponent module, - String moduleName, - InjectionServices injectionServices) { - return new InjectionModuleServiceProvider(module, moduleName, injectionServices); - } - - private ServiceProvider createServiceProvider(Application app, - InjectionServices injectionServices) { - return new InjectionApplicationServiceProvider(app, injectionServices); - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/Dependencies.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/Dependencies.java deleted file mode 100644 index dcdb8e5e0dc..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/Dependencies.java +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.lang.annotation.Annotation; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.DependencyInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfoCriteria; - -/** - * This is the class the code-generator will target that will be used at runtime for a service provider to build up its - * dependencies expressed as {@link DependenciesInfo}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class Dependencies { - - private Dependencies() { - } - - /** - * Creates a builder. - * - * @param serviceTypeName the service type name - * @return the fluent builder - */ - public static BuilderContinuation builder(TypeName serviceTypeName) { - Objects.requireNonNull(serviceTypeName); - return new BuilderContinuation(serviceTypeName); - } - - /** - * Creates a builder. - * - * @param serviceType the service type - * @return the fluent builder - */ - public static BuilderContinuation builder(Class serviceType) { - Objects.requireNonNull(serviceType); - return builder(TypeName.create(serviceType)); - } - - /** - * Combine the dependency info from the two sources to create a merged set of dependencies. - * - * @param parentDeps the parent set of dependencies - * @param deps the child set of dependencies - * @return the combined set - */ - public static DependenciesInfo combine(DependenciesInfo parentDeps, - DependenciesInfo deps) { - Objects.requireNonNull(parentDeps); - Objects.requireNonNull(deps); - - DependenciesInfo.Builder builder = (deps instanceof DependenciesInfo.Builder) - ? (DependenciesInfo.Builder) deps - : DependenciesInfo.builder(deps); - parentDeps.serviceInfoDependencies().forEach(builder::addServiceInfoDependencies); - return builder.build(); - } - - static String toBaseIdentity(InjectionPointInfo.Builder dep) { - ElementKind kind = dep.elementKind().orElseThrow(); - String elemName = dep.elementName().orElseThrow(); - AccessModifier access = dep.access().orElseThrow(); - String packageName = toPackageName(dep.serviceTypeName().orElseThrow()); - - String baseId; - if (ElementKind.FIELD == kind) { - baseId = toFieldIdentity(elemName, packageName); - } else { - baseId = toMethodBaseIdentity(elemName, - dep.elementArgs().orElseThrow(), - access, packageName); - } - return baseId; - } - - static String toId(InjectionPointInfo.Builder dep) { - ElementKind kind = dep.elementKind().orElseThrow(); - String elemName = dep.elementName().orElseThrow(); - AccessModifier access = dep.access().orElseThrow(); - String packageName = toPackageName(dep.serviceTypeName().orElseThrow()); - - String id; - if (ElementKind.FIELD == kind) { - id = toFieldIdentity(elemName, packageName); - } else { - id = toMethodIdentity(elemName, - dep.elementArgs().orElseThrow(), - dep.elementOffset().orElseThrow(() -> new IllegalStateException("Failed on " + elemName)), - access, - packageName); - } - return id; - } - - /** - * The field's identity and its base identity are the same since there is no arguments to handle. - * - * @param elemName the non-null field name - * @param packageName the package name of the owning service type containing the field - * @return the field identity (relative to the owning service type) - */ - public static String toFieldIdentity(String elemName, - String packageName) { - String id = Objects.requireNonNull(elemName); - - if (packageName != null) { - id = packageName + "." + id; - } - return id; - } - - /** - * Computes the base identity given the method name and the number of arguments to the method. - * - * @param elemName the method name - * @param methodArgCount the number of arguments to the method - * @param access the method's access - * @param packageName the method's enclosing package name - * @return the base identity (relative to the owning service type) - */ - public static String toMethodBaseIdentity(String elemName, - int methodArgCount, - AccessModifier access, - String packageName) { - String id = Objects.requireNonNull(elemName) + "|" + methodArgCount; - if (AccessModifier.PACKAGE_PRIVATE == access || elemName.equals(InjectionPointInfo.CONSTRUCTOR)) { - if (packageName != null) { - id = packageName + "." + id; - } - } - return id; - } - - /** - * Computes the method's unique identity, taking into consideration the number of args it accepts - * plus any optionally provided specific argument offset position. - * - * @param elemName the method name - * @param methodArgCount the number of arguments to the method - * @param elemOffset the optional parameter offset - * @param access the access for the method - * @param packageName the package name of the owning service type containing the method - * @return the unique identity (relative to the owning service type) - */ - public static String toMethodIdentity(String elemName, - int methodArgCount, - Integer elemOffset, - AccessModifier access, - String packageName) { - String result = toMethodBaseIdentity(elemName, methodArgCount, access, packageName); - - if (elemOffset == null) { - return result; - } - - assert (elemOffset <= methodArgCount) : result; - return result + "(" + elemOffset + ")"; - } - - private static String toPackageName(TypeName typeName) { - String packageName = typeName.packageName(); - return packageName.isBlank() ? null : packageName; - } - - /** - * The continuation builder. This is a specialized builder used within the generated {@link Activator}. - * It is specialized in that it validates and decorates over the normal builder, and provides a more streamlined interface. - */ - public static class BuilderContinuation { - private DependenciesInfo.Builder builder; - private InjectionPointInfo.Builder ipInfoBuilder; - - private BuilderContinuation(TypeName serviceTypeName) { - this.builder = DependenciesInfo.builder() - .fromServiceTypeName(serviceTypeName); - } - - /** - * Adds a new dependency item. - * - * @param elemName the element name - * @param elemType the element type - * @param kind the element kind - * @param access the element access - * @return the builder - */ - // note: called from generated code - public BuilderContinuation add(String elemName, - Class elemType, - ElementKind kind, - AccessModifier access) { - if (ElementKind.FIELD != kind && Void.class != elemType) { - throw new IllegalStateException("Should not use this for method element types"); - } - TypeName fromServiceTypeName = builder.fromServiceTypeName().orElseThrow(); - return add(fromServiceTypeName, elemName, TypeName.create(elemType), kind, 0, access); - } - - /** - * Adds a new dependency item. - * - * @param elemName the element name - * @param elemType the element type - * @param kind the element kind - * @param elemArgs for methods, the number of arguments the method takes - * @param access the element access - * @return the builder - */ - // note: called from generated code - public BuilderContinuation add(String elemName, - Class elemType, - ElementKind kind, - int elemArgs, - AccessModifier access) { - if (ElementKind.FIELD == kind && 0 != elemArgs) { - throw new IllegalStateException("Should not have any arguments for field types: " + elemName); - } - TypeName fromServiceTypeName = builder.fromServiceTypeName().orElseThrow(); - return add(fromServiceTypeName, elemName, TypeName.create(elemType), kind, elemArgs, access); - } - - /** - * Adds a new dependency item. - * - * @param serviceType the service type - * @param elemName the element name - * @param elemType the element type - * @param kind the element kind - * @param access the element access - * @return the builder - */ - // note: called from generated code - public BuilderContinuation add(Class serviceType, - String elemName, - Class elemType, - ElementKind kind, - AccessModifier access) { - if (ElementKind.FIELD != kind) { - throw new IllegalStateException("Should not use this for method element types"); - } - return add(TypeName.create(serviceType), elemName, TypeName.create(elemType), kind, 0, access); - } - - /** - * Adds a new dependency item. - * - * @param serviceType the service type - * @param elemName the element name - * @param elemType the element type - * @param kind the element kind - * @param elemArgs used for methods only; the number of arguments the method accepts - * @param access the element access - * @return the builder - */ - // note: called from generated code - public BuilderContinuation add(Class serviceType, - String elemName, - Class elemType, - ElementKind kind, - int elemArgs, - AccessModifier access) { - return add(TypeName.create(serviceType), elemName, TypeName.create(elemType), kind, elemArgs, access); - } - - /** - * Adds a new dependency item. - * - * @param ipInfo the injection point info already built - * @return the builder - */ - public BuilderContinuation add(InjectionPointInfo ipInfo) { - commitLastDependency(); - - ipInfoBuilder = InjectionPointInfo.builder(ipInfo); - return this; - } - - /** - * Sets the element offset. - * - * @param offset the offset - * @return the builder - */ - // note: called from generated code - public BuilderContinuation elemOffset(int offset) { - ipInfoBuilder.elementOffset(offset); - return this; - } - - /** - * Sets the flag indicating the injection point is a list. - * - * @return the builder - */ - // note: called from generated code - public BuilderContinuation listWrapped() { - return listWrapped(true); - } - - /** - * Sets the flag indicating the injection point is a list. - * - * @param val true if list type - * @return the builder - */ - // note: called from generated code - public BuilderContinuation listWrapped(boolean val) { - ipInfoBuilder.listWrapped(val); - return this; - } - - /** - * Sets the flag indicating the injection point is a provider. - * - * @return the builder - */ - // note: called from generated code - public BuilderContinuation providerWrapped() { - return providerWrapped(true); - } - - /** - * Sets the flag indicating the injection point is a provider. - * - * @param val true if provider type - * @return the builder - */ - // note: called from generated code - public BuilderContinuation providerWrapped(boolean val) { - ipInfoBuilder.providerWrapped(val); - return this; - } - - /** - * Sets the flag indicating the injection point is an {@link java.util.Optional} type. - * - * @return the builder - */ - // note: called from generated code - public BuilderContinuation optionalWrapped() { - return optionalWrapped(true); - } - - /** - * Sets the flag indicating the injection point is an {@link java.util.Optional} type. - * - * @param val true if list type - * @return the builder - */ - // note: called from generated code - public BuilderContinuation optionalWrapped(boolean val) { - ipInfoBuilder.optionalWrapped(val); - return this; - } - - /** - * Sets the optional qualified name of the injection point. - * - * @param val the name - * @return the builder - */ - public BuilderContinuation named(String val) { - ipInfoBuilder.addQualifier(Qualifier.createNamed(val)); - return this; - } - - /** - * Sets the optional qualifier of the injection point. - * - * @param val the qualifier - * @return the builder - */ - // note: called from generated code - public BuilderContinuation addQualifier(Class val) { - ipInfoBuilder.addQualifier(Qualifier.create(val)); - return this; - } - - /** - * Sets the optional qualifier of the injection point. - * - * @param val the qualifier - * @return the builder - */ - // note: called from generated code - public BuilderContinuation addQualifier(Qualifier val) { - ipInfoBuilder.addQualifier(val); - return this; - } - - /** - * Sets the optional qualifier of the injection point. - * - * @param val the qualifier - * @return the builder - */ - public BuilderContinuation qualifiers(Set val) { - ipInfoBuilder.qualifiers(val); - return this; - } - - /** - * Sets the flag indicating that the injection point is static. - * - * @param val flag indicating if static - * @return the builder - */ - public BuilderContinuation staticDeclaration(boolean val) { - ipInfoBuilder.staticDeclaration(val); - return this; - } - - /** - * Name of the injection point code, such as argument or field. - * - * @param name name of the field or argument (if available) - * @return the builder - */ - public BuilderContinuation ipName(String name) { - ipInfoBuilder.ipName(name); - return this; - } - - /** - * Type of the injection point code, such as argument or field. - * - * @param type of the injection point, including all generic type arguments - * @return the builder - */ - public BuilderContinuation ipType(TypeName type) { - ipInfoBuilder.ipType(type); - return this; - } - - /** - * Commits the last dependency item, and prepares for the next. - * - * @return the builder - */ - public DependenciesInfo build() { - assert (builder != null); - - commitLastDependency(); - DependenciesInfo deps = builder.build(); - builder = null; - return deps; - } - - /** - * Adds a new dependency item. - * - * @param serviceTypeName the service type - * @param elemName the element name - * @param elemTypeName the element type - * @param kind the element kind - * @param elemArgs used for methods only; this is the number of arguments the method accepts - * @param access the element access - * @return the builder - */ - public BuilderContinuation add(TypeName serviceTypeName, - String elemName, - TypeName elemTypeName, - ElementKind kind, - int elemArgs, - AccessModifier access) { - commitLastDependency(); - - // thus begins a new builder continuation round - ipInfoBuilder = InjectionPointInfo.builder() - .serviceTypeName(serviceTypeName) - .access(access) - .elementKind(kind) - .elementTypeName(elemTypeName) - .elementName(elemName) - .update(builder -> { - if (ElementKind.FIELD != kind) { - builder.elementOffset(0); - } - }) - .elementArgs(elemArgs); - return this; - } - - /** - * Commits the last dependency item to complete the last builder continuation. - * - * @return any built dependencies info realized from this last commit - */ - // note: called from generated code - public Optional commitLastDependency() { - String id = null; - - InjectionPointInfo.Builder previousBuilder = ipInfoBuilder; - try { - assert (builder != null); - - if (ipInfoBuilder != null) { - id = toId(ipInfoBuilder); - ipInfoBuilder.baseIdentity(toBaseIdentity(ipInfoBuilder)); - ipInfoBuilder.id(id); - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addContractImplemented(ipInfoBuilder.elementTypeName().orElseThrow()) - .qualifiers(ipInfoBuilder.qualifiers()) - .build(); - - InjectionPointInfo ipInfo = ipInfoBuilder - .dependencyToServiceInfo(criteria) - .build(); - ipInfoBuilder = null; - - DependencyInfo dep = DependencyInfo.builder() - .elementName(ipInfo.ipName()) - .addInjectionPointDependency(ipInfo) - .dependencyTo(ipInfo.dependencyToServiceInfo()) - .build(); - - builder.addServiceInfoDependency(ipInfo.dependencyToServiceInfo(), dep); - return Optional.of(dep); - } - - return Optional.empty(); - } catch (Exception e) { - throw new IllegalStateException("Failed to commit a dependency for id: " - + id + ", failed builder: " + previousBuilder, e); - } - } - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/HelidonInjectionPlanBlueprint.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/HelidonInjectionPlanBlueprint.java deleted file mode 100644 index 9bb27667c7c..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/HelidonInjectionPlanBlueprint.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.List; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.inject.spi.InjectionPlan; - -/** - * The injection plan for a given service provider and element belonging to that service provider. This plan can be created during - * compile-time, and then just loaded from the {@link io.helidon.inject.api.Application} during Injection bootstrap initialization, or it - * can be produced during the same startup processing sequence if the Application was not found, or if it was not permitted to be - * loaded. - */ -@Prototype.Blueprint -interface HelidonInjectionPlanBlueprint extends InjectionPlan { - - /** - * The list of services/providers that are unqualified to satisfy the given injection point but were considered. - * - * @return the unqualified services/providers for this injection point - */ - @Option.Singular - List unqualifiedProviders(); - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/HelidonInjectionStartupProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/HelidonInjectionStartupProvider.java deleted file mode 100644 index 976ed6959ab..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/HelidonInjectionStartupProvider.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.inject.api.Helidon; -import io.helidon.spi.HelidonStartupProvider; - -/** - * Service provider implementation, should only be used from {@link java.util.ServiceLoader}. - * See {@link Helidon} type to discover programmatic API. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class HelidonInjectionStartupProvider implements HelidonStartupProvider { - /** - * Required default constructor needed for {@link java.util.ServiceLoader}. - * - * @deprecated please do not use directly - */ - @Deprecated - public HelidonInjectionStartupProvider() { - } - - @Override - public void start(String[] arguments) { - Helidon.start(); - } -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionApplicationServiceProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionApplicationServiceProvider.java deleted file mode 100644 index 510c3183b56..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionApplicationServiceProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfo; - -/** - * Basic {@link Application} implementation. An application is-a service provider also. - */ -class InjectionApplicationServiceProvider extends AbstractServiceProvider { - - InjectionApplicationServiceProvider(Application app, InjectionServices injectionServices) { - super(app, Phase.ACTIVE, createServiceInfo(app), injectionServices); - serviceRef(app); - } - - static ServiceInfo createServiceInfo(Application app) { - ServiceInfo.Builder builder = ServiceInfo.builder() - .serviceTypeName(app.getClass()) - .addContractImplemented(TypeName.create(Application.class)); - app.named().ifPresent(name -> builder.addQualifier(Qualifier.createNamed(name))); - return builder.build(); - } - - @Override - public Class serviceType() { - return Application.class; - } -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionExceptions.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionExceptions.java deleted file mode 100644 index 8cff0f052f7..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionExceptions.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Objects; - -import io.helidon.inject.api.CallingContext; - -import static io.helidon.inject.api.InjectionServicesHolder.DEBUG_HINT; - -/** - * Utility for exceptions with information about debugging. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public final class InjectionExceptions { - private InjectionExceptions() { - } - - /** - * Convenience method for producing an error message that may involve advising the user to apply a debug mode. - * - * @param callingContext the calling context (caller can be using a custom calling context, which is why we accept it here - * instead of using the global one) - * @param msg the base message to display - * @return the message appropriate for any exception being thrown - */ - public static String toErrorMessage(CallingContext callingContext, String msg) { - Objects.requireNonNull(callingContext); - Objects.requireNonNull(msg); - - return msg + " - previous calling context: " + callingContext; - } - - /** - * Convenience method for producing an error message that may involve advising the user to apply a debug mode. Use - * {@link #toErrorMessage(CallingContext, String)} instead f a calling context is available. - * - * @param msg the base message to display - * @return the message appropriate for any exception being thrown - * @see #toErrorMessage(CallingContext, String) - */ - public static String toErrorMessage(String msg) { - Objects.requireNonNull(msg); - - return msg + " - " + DEBUG_HINT; - } -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionModuleServiceProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionModuleServiceProvider.java deleted file mode 100644 index 894dbacffa4..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/InjectionModuleServiceProvider.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfo; - -/** - * Basic {@link ModuleComponent} implementation. A ModuleComponent is-a service provider also. - */ -class InjectionModuleServiceProvider extends AbstractServiceProvider { - - InjectionModuleServiceProvider(ModuleComponent module, - String moduleName, - InjectionServices injectionServices) { - super(module, InjectionServices.terminalActivationPhase(), createServiceInfo(module, moduleName), injectionServices); - serviceRef(module); - } - - static ServiceInfo createServiceInfo(ModuleComponent module, - String moduleName) { - ServiceInfo.Builder builder = ServiceInfo.builder() - .serviceTypeName(TypeName.create(module.getClass())) - .addContractImplemented(TypeName.create(ModuleComponent.class)); - if (moduleName != null) { - builder.moduleName(moduleName) - .addQualifier(Qualifier.createNamed(moduleName)); - } - return builder.build(); - } - - @Override - public Class serviceType() { - return ModuleComponent.class; - } -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/InterceptedMethod.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/InterceptedMethod.java deleted file mode 100644 index ec33ede576e..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/InterceptedMethod.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.List; -import java.util.Objects; -import java.util.function.Function; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.ServiceProvider; - -import jakarta.inject.Provider; - -/** - * Base class, used in {@link Interceptor} generated code. One of these instances will be created for each - * intercepted method. - * - * @param the intercepted type - * @param the intercepted method return type - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public abstract class InterceptedMethod implements Function { - private final I impl; - private final InvocationContext ctx; - - /** - * The constructor. - * - * @param interceptedImpl the intercepted instance - * @param serviceProvider the service provider for the intercepted type - * @param serviceTypeName the service type name - * @param serviceLevelAnnotations the service level annotations - * @param interceptors the interceptors for the method - * @param methodInfo the method element info - * @param methodArgInfo the method args element info - */ - protected InterceptedMethod(I interceptedImpl, - ServiceProvider serviceProvider, - TypeName serviceTypeName, - List serviceLevelAnnotations, - List> interceptors, - TypedElementInfo methodInfo, - List methodArgInfo) { - this.impl = Objects.requireNonNull(interceptedImpl); - this.ctx = InvocationContext.builder() - .serviceProvider(serviceProvider) - .serviceTypeName(serviceTypeName) - .classAnnotations(serviceLevelAnnotations) - .interceptors(interceptors) - .elementInfo(methodInfo) - .elementArgInfo(methodArgInfo) - .build(); - } - - /** - * The constructor. - * - * @param interceptedImpl the intercepted instance - * @param serviceProvider the service provider for the intercepted type - * @param serviceTypeName the service type name - * @param serviceLevelAnnotations the service level annotations - * @param interceptors the interceptors for the method - * @param methodInfo the method element info - */ - protected InterceptedMethod(I interceptedImpl, - ServiceProvider serviceProvider, - TypeName serviceTypeName, - List serviceLevelAnnotations, - List> interceptors, - TypedElementInfo methodInfo) { - this.impl = Objects.requireNonNull(interceptedImpl); - this.ctx = InvocationContext.builder() - .serviceProvider(serviceProvider) - .serviceTypeName(serviceTypeName) - .classAnnotations(serviceLevelAnnotations) - .interceptors(interceptors) - .elementInfo(methodInfo) - .build(); - } - - /** - * The intercepted instance. - * - * @return the intercepted instance - */ - public I impl() { - return impl; - } - - /** - * The intercepted invocation context. - * - * @return the intercepted invocation context - */ - public InvocationContext ctx() { - return ctx; - } - - /** - * Make the invocation to an interceptor method. - * - * @param args arguments - * @return the result of the call to the intercepted method - * @throws java.lang.Throwable if there is any throwables encountered as part of the invocation - */ - public abstract V invoke(Object... args) throws Throwable; - - @Override - public V apply(Object... args) { - try { - return invoke(args); - } catch (Throwable t) { - boolean targetWasCalledSuccessfully = false; - if (t instanceof InvocationException) { - targetWasCalledSuccessfully = ((InvocationException) t).targetWasCalled(); - } - - throw new InvocationException(t.getMessage(), t, ctx.serviceProvider(), targetWasCalledSuccessfully); - } - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/Invocation.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/Invocation.java deleted file mode 100644 index 8e8ba597655..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/Invocation.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; - -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.ServiceProvider; - -import jakarta.inject.Provider; - -/** - * Handles the invocation of {@link Interceptor} methods. - * Note that upon a successful call to the {@link Interceptor.Chain#proceed(Object[])} or to the ultimate - * target, the invocation will be prevented from being executed again. - * - * @see InvocationContext - * @param the invocation type - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class Invocation implements Interceptor.Chain { - private final InvocationContext ctx; - private final List> interceptors; - private int interceptorPos; - private Function call; - - private Invocation(InvocationContext ctx, - Function call) { - this.ctx = ctx; - this.call = Objects.requireNonNull(call); - this.interceptors = List.copyOf(ctx.interceptors()); - } - - @Override - public String toString() { - return String.valueOf(ctx.elementInfo()); - } - - /** - * Creates an instance of {@link Invocation} and invokes it in this context. - * - * @param ctx the invocation context - * @param call the call to the base service provider's method - * @param args the call arguments - * @param the type returned from the method element - * @return the invocation instance - * @throws InvocationException if there are errors during invocation chain processing - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public static V createInvokeAndSupply(InvocationContext ctx, - Function call, - Object[] args) { - if (ctx.interceptors().isEmpty()) { - try { - return call.apply(args); - } catch (Throwable t) { - throw new InvocationException("Error in interceptor chain processing", t, true); - } - } else { - return (V) new Invocation(ctx, call).proceed(args); - } - } - - /** - * The degenerate case for {@link #mergeAndCollapse(List[])}. This is here only to eliminate the unchecked varargs compiler - * warnings that would otherwise be issued in code that does not have any interceptors on a method. - * - * @param the type of the provider - * @return an empty list - * @deprecated this method should only be called by generated code - */ - @Deprecated - public static List> mergeAndCollapse() { - return List.of(); - } - - /** - * Merges a variable number of lists together, where the net result is the merged set of non-null providers - * ranked in proper weight order, or else empty list. - * - * @param lists the lists to merge - * @param the type of the provider - * @return the merged result or empty list if there is o interceptor providers - */ - @SuppressWarnings("unchecked") - public static List> mergeAndCollapse(List>... lists) { - List> result = null; - - for (List> list : lists) { - if (list == null) { - continue; - } - - for (Provider p : list) { - if (p == null) { - continue; - } - - if (p instanceof ServiceProvider - && VoidServiceProvider.serviceTypeName().equals( - ((ServiceProvider) p).serviceInfo().serviceTypeName())) { - continue; - } - - if (result == null) { - result = new ArrayList<>(); - } - if (!result.contains(p)) { - result.add(p); - } - } - } - - if (result != null && result.size() > 1) { - result.sort(DefaultServices.serviceProviderComparator()); - } - - return (result != null) ? Collections.unmodifiableList(result) : List.of(); - } - - @Override - public V proceed(Object... args) { - if (this.call == null) { - throw new InvocationException("Duplicate invocation, or unknown call type: " + this, true); - } - - if (interceptorPos < interceptors.size()) { - Provider interceptorProvider = interceptors.get(interceptorPos); - Interceptor interceptor = interceptorProvider.get(); - interceptorPos++; - try { - return interceptor.proceed(ctx, this, args); - } catch (Throwable t) { - interceptorPos--; - - if (t instanceof InvocationException) { - throw t; - } - - throw (interceptorProvider instanceof ServiceProvider) - ? new InvocationException("Error in interceptor chain processing", - t, - (ServiceProvider) interceptorProvider, - call == null) - : new InvocationException("Error in interceptor chain processing", - t, - call == null); - } - } - - Function call = this.call; - this.call = null; - - try { - return call.apply(args); - } catch (Throwable t) { - if (t instanceof InvocationException) { - if (!((InvocationException) t).targetWasCalled()) { - // allow the call to happen again - this.call = call; - } - throw t; - } - - // allow the call to happen again - this.call = call; - throw new InvocationException("Error in interceptor chain processing", t, true); - } - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/NonSingletonServiceProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/NonSingletonServiceProvider.java deleted file mode 100644 index 5311d837e7c..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/NonSingletonServiceProvider.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Phase; - -/** - * A provider that represents a non-singleton service. - * - * @param the type of the service this provider manages - */ -class NonSingletonServiceProvider extends AbstractServiceProvider { - @SuppressWarnings("FieldCanBeLocal") - private final AbstractServiceProvider delegate; - - private NonSingletonServiceProvider(AbstractServiceProvider delegate) { - this.delegate = delegate; - injectionServices(delegate.injectionServices()); - serviceInfo(delegate.serviceInfo()); - dependencies(delegate.dependencies()); - } - - static T createAndActivate(AbstractServiceProvider delegate) { - NonSingletonServiceProvider serviceProvider = new NonSingletonServiceProvider<>(delegate); - - LogEntryAndResult logEntryAndResult = serviceProvider.createLogEntryAndResult(Phase.ACTIVE); - serviceProvider.startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVATION_STARTING); - - serviceProvider.startTransitionCurrentActivationPhase(logEntryAndResult, Phase.GATHERING_DEPENDENCIES); - Map plans = delegate.getOrCreateInjectionPlan(false); - logEntryAndResult.activationResult().injectionPlans(plans); - Map deps = delegate.resolveDependencies(plans); - logEntryAndResult.activationResult().resolvedDependencies(deps); - serviceProvider.finishedTransitionCurrentActivationPhase(logEntryAndResult); - - serviceProvider.startTransitionCurrentActivationPhase(logEntryAndResult, Phase.CONSTRUCTING); - T instance = delegate.createServiceProvider(deps); - serviceProvider.finishedTransitionCurrentActivationPhase(logEntryAndResult); - - if (instance != null) { - serviceProvider.startTransitionCurrentActivationPhase(logEntryAndResult, Phase.INJECTING); - List serviceTypeOrdering = Objects.requireNonNull(delegate.serviceTypeInjectionOrder()); - LinkedHashSet injections = new LinkedHashSet<>(); - serviceTypeOrdering.forEach((forServiceType) -> { - delegate.doInjectingFields(instance, deps, injections, forServiceType); - delegate.doInjectingMethods(instance, deps, injections, forServiceType); - }); - serviceProvider.finishedTransitionCurrentActivationPhase(logEntryAndResult); - - serviceProvider.startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVATION_STARTING); - - serviceProvider.startTransitionCurrentActivationPhase(logEntryAndResult, Phase.POST_CONSTRUCTING); - serviceProvider.doPostConstructing(logEntryAndResult); - serviceProvider.finishedTransitionCurrentActivationPhase(logEntryAndResult); - - serviceProvider.startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVATION_FINISHING); - } - - serviceProvider.startAndFinishTransitionCurrentActivationPhase(logEntryAndResult, Phase.ACTIVE); - - return instance; - } - - @Override - public Class serviceType() { - return delegate.serviceType(); - } -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceBinderDefault.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceBinderDefault.java deleted file mode 100644 index bc4b57507ce..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceBinderDefault.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Objects; -import java.util.Optional; - -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.ServiceBinder; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; -import io.helidon.inject.api.Services; - -/** - * The default implementation for {@link ServiceBinder}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class ServiceBinderDefault implements ServiceBinder { - private final InjectionServices injectionServices; - private final ServiceBinder serviceRegistry; - private final String moduleName; - private final boolean trusted; - - private ServiceBinderDefault(InjectionServices injectionServices, - String moduleName, - boolean trusted) { - this.injectionServices = injectionServices; - this.serviceRegistry = (ServiceBinder) injectionServices.services(); - this.moduleName = moduleName; - this.trusted = trusted; - } - - /** - * Creates an instance of the default services binder. - * - * @param injectionServices the services registry instance - * @param moduleName the module name - * @param trusted are we in trusted mode (typically only set during early initialization sequence) - * @return the newly created service binder - */ - public static ServiceBinderDefault create(InjectionServices injectionServices, - String moduleName, - boolean trusted) { - Objects.requireNonNull(injectionServices); - Objects.requireNonNull(moduleName); - return new ServiceBinderDefault(injectionServices, moduleName, trusted); - } - - @Override - public void bind(ServiceProvider sp) { - if (!trusted) { - DefaultServices.assertPermitsDynamic(injectionServices.config()); - } - - Optional> bindableSp = toBindableProvider(sp); - if (bindableSp.isPresent() && alreadyBoundToThisInjectionServices(bindableSp.get(), injectionServices)) { - return; - } - - if (moduleName != null) { - bindableSp.ifPresent(it -> it.moduleName(moduleName)); - } - - Services services = injectionServices.services(); - if (services instanceof DefaultServices && sp instanceof ServiceProviderBindable) { - Phase currentPhase = ((DefaultServices) services).currentPhase(); - if (currentPhase.ordinal() >= Phase.SERVICES_READY.ordinal()) { - // deferred binding (e.g., to allow InjectionTestSupport to programmatically register/bind service providers - ((ServiceProviderBindable) sp).injectionServices(Optional.of(injectionServices)); - } - } - - serviceRegistry.bind(sp); - bindableSp.ifPresent(it -> it.injectionServices(Optional.of(injectionServices))); - } - - private boolean alreadyBoundToThisInjectionServices(ServiceProviderBindable serviceProvider, - InjectionServices injectionServices) { - InjectionServices assigned = serviceProvider.injectionServices().orElse(null); - return (assigned == injectionServices); - } - - /** - * Returns the bindable service provider for what is passed if available. - * - * @param sp the service provider - * @return the bindable service provider if available, otherwise empty - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public static Optional> toBindableProvider(ServiceProvider sp) { - Objects.requireNonNull(sp); - if (sp instanceof ServiceProviderBindable) { - return Optional.of((ServiceProviderBindable) sp); - } - return (Optional) sp.serviceProviderBindable(); - } - - /** - * Returns the root provider of the service provider passed. - * - * @param sp the service provider - * @return the root provider of the service provider, falling back to the service provider passed - */ - public static ServiceProvider toRootProvider(ServiceProvider sp) { - Optional> bindable = toBindableProvider(sp); - if (bindable.isPresent()) { - sp = bindable.get(); - } - - ServiceProvider rootProvider = ((ServiceProviderBindable) sp).rootProvider().orElse(null); - return (rootProvider != null) ? rootProvider : sp; - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceProviderComparator.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceProviderComparator.java deleted file mode 100644 index 8648d00ebab..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceProviderComparator.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.io.Serializable; -import java.util.Comparator; - -import io.helidon.common.Weights; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceProvider; - -import jakarta.inject.Provider; - -/** - * A comparator appropriate for service providers, first using its {@link io.helidon.common.Weight} and then service type name - * to determine its natural ordering. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class ServiceProviderComparator implements Comparator>, Serializable { - private static final ServiceProviderComparator INSTANCE = new ServiceProviderComparator(); - - private ServiceProviderComparator() { - } - - /** - * Returns a service provider comparator. - * - * @return the service provider comparator - */ - public static ServiceProviderComparator create() { - return INSTANCE; - } - - @Override - public int compare(Provider p1, - Provider p2) { - if (p1 == p2) { - return 0; - } - - if (p1 instanceof ServiceProvider - && p2 instanceof ServiceProvider) { - ServiceProvider sp1 = (ServiceProvider) p1; - ServiceProvider sp2 = (ServiceProvider) p2; - - ServiceInfo info1 = sp1.serviceInfo(); - ServiceInfo info2 = sp2.serviceInfo(); - if (info1 == info2) { - return 0; - } - - double w1 = info1.realizedWeight(); - double w2 = info2.realizedWeight(); - int comp = Double.compare(w1, w2); - if (0 != comp) { - return -1 * comp; - } - // secondary ordering based upon its name... - TypeName name1 = info1.serviceTypeName(); - TypeName name2 = info2.serviceTypeName(); - comp = name2.compareTo(name1); - return -1 * comp; - } else { - return Weights.weightComparator().compare(p1, p2); - } - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceUtils.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceUtils.java deleted file mode 100644 index 2f5c65aa74a..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/ServiceUtils.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceProvider; - -/** - * Public helpers around shared services usages. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public final class ServiceUtils { - private static final TypeName MODULE_COMPONENT = TypeName.create(ModuleComponent.class); - private static final TypeName APPLICATION = TypeName.create(ModuleComponent.class); - - private ServiceUtils() { - } - - /** - * Determines if the service provider is valid to receive injections. - * - * @param sp the service provider - * @return true if the service provider can receive injection - */ - public static boolean isQualifiedInjectionTarget(ServiceProvider sp) { - ServiceInfo serviceInfo = sp.serviceInfo(); - Set contractsImplemented = serviceInfo.contractsImplemented(); - DependenciesInfo deps = sp.dependencies(); - return (deps != AbstractServiceProvider.NO_DEPS) - || (!contractsImplemented.isEmpty() - && !contractsImplemented.contains(MODULE_COMPONENT) - && !contractsImplemented.contains(APPLICATION)); - } - - /** - * Provides a {@link ServiceProvider#description()}, falling back to {@link #toString()} on the passed - * provider argument. - * - * @param provider the provider - * @return the description - */ - public static String toDescription(Object provider) { - if (provider instanceof Optional) { - provider = ((Optional) provider).orElse(null); - } - - if (provider instanceof ServiceProvider) { - return ((ServiceProvider) provider).description(); - } - return String.valueOf(provider); - } - - /** - * Provides a {@link ServiceProvider#description()}, falling back to {@link #toString()} on the passed - * provider argument. - * - * @param coll the collection of providers - * @return the description - */ - public static List toDescriptions(Collection coll) { - return coll.stream().map(ServiceUtils::toDescription).collect(Collectors.toList()); - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/State.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/State.java deleted file mode 100644 index c8aff3c7665..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/State.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Objects; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.Resettable; - -class State implements Resettable, Cloneable { - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - private Phase currentPhase; - private boolean isFinished; - private Throwable lastError; - - private State() { - } - - static State create(Phase phase) { - return new State().currentPhase(phase); - } - - @Override - public State clone() { - ReentrantReadWriteLock.ReadLock rlock = lock.readLock(); - rlock.lock(); - try { - return create(currentPhase()).finished(finished()).lastError(lastError()); - } finally { - rlock.unlock(); - } - } - - @Override - public String toString() { - ReentrantReadWriteLock.WriteLock rlock = lock.writeLock(); - rlock.lock(); - try { - return "currentPhase=" + currentPhase + ", isFinished=" + isFinished + ", lastError=" + lastError; - } finally { - rlock.unlock(); - } - } - - @Override - public boolean reset(boolean deep) { - ReentrantReadWriteLock.WriteLock wlock = lock.writeLock(); - wlock.lock(); - try { - currentPhase(Phase.INIT).finished(false).lastError(null); - return true; - } finally { - wlock.unlock(); - } - } - - State currentPhase(Phase phase) { - ReentrantReadWriteLock.WriteLock wlock = lock.writeLock(); - wlock.lock(); - try { - Phase lastPhase = this.currentPhase; - this.currentPhase = Objects.requireNonNull(phase); - if (lastPhase != this.currentPhase) { - this.isFinished = false; - this.lastError = null; - } - return this; - } finally { - wlock.unlock(); - } - } - - Phase currentPhase() { - ReentrantReadWriteLock.ReadLock rlock = lock.readLock(); - rlock.lock(); - try { - return currentPhase; - } finally { - rlock.unlock(); - } - } - - State finished(boolean finished) { - ReentrantReadWriteLock.WriteLock wlock = lock.writeLock(); - wlock.lock(); - try { - this.isFinished = finished; - return this; - } finally { - wlock.unlock(); - } - } - - boolean finished() { - ReentrantReadWriteLock.ReadLock rlock = lock.readLock(); - rlock.lock(); - try { - return isFinished; - } finally { - rlock.unlock(); - } - } - - State lastError(Throwable t) { - ReentrantReadWriteLock.WriteLock wlock = lock.writeLock(); - wlock.lock(); - try { - this.lastError = t; - return this; - } finally { - wlock.unlock(); - } - } - - Throwable lastError() { - ReentrantReadWriteLock.ReadLock rlock = lock.readLock(); - rlock.lock(); - try { - return lastError; - } finally { - rlock.unlock(); - } - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/Versions.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/Versions.java deleted file mode 100644 index d636a2a04f0..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/Versions.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -/** - * Keeps track of the Injection Interop Versions. - *

- * Since Helidon Injection performs code-generation, each previously generated artifact version may need to be discoverable in order - * to determine interoperability with previous release versions. This class will only track version changes for anything that might - * affect interoperability - it will not be rev'ed for general code enhancements and fixes. - *

- * Please note that this version is completely independent of the Helidon version and other features and modules within Helidon. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class Versions { - - /** - * Version 1 - the initial release of Injection. - */ - public static final String INJECT_VERSION_1 = "1"; - - /** - * The current release is {@link #INJECT_VERSION_1}. - */ - public static final String CURRENT_INJECT_VERSION = INJECT_VERSION_1; - - private Versions() { - } - -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/VoidServiceProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/VoidServiceProvider.java deleted file mode 100644 index f02dad6ad10..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/VoidServiceProvider.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceProvider; - -import jakarta.inject.Singleton; - -/** - * A proxy service provider created internally by the framework. - */ -class VoidServiceProvider extends AbstractServiceProvider { - static final VoidServiceProvider INSTANCE = new VoidServiceProvider() {}; - static final List> LIST_INSTANCE = List.of(INSTANCE); - - private VoidServiceProvider() { - serviceInfo(ServiceInfo.builder() - .serviceTypeName(Void.class) - .addContractImplemented(serviceTypeName()) - .activatorTypeName(VoidServiceProvider.class) - .addScopeTypeName(Singleton.class) - .declaredWeight(DEFAULT_WEIGHT) - .build()); - } - - public static TypeName serviceTypeName() { - return TypeName.create(Void.class); - } - - @Override - protected Void createServiceProvider(Map resolvedDeps) { - // this must return null by definition - return null; - } - - @Override - public Optional first(ContextualServiceQuery query) { - return Optional.empty(); - } - - @Override - public Class serviceType() { - return Void.class; - } -} diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/package-info.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/package-info.java deleted file mode 100644 index e2e28ff5e05..00000000000 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection runtime services. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -package io.helidon.inject.runtime; diff --git a/inject/runtime/src/main/java/module-info.java b/inject/runtime/src/main/java/module-info.java deleted file mode 100644 index 743629eac86..00000000000 --- a/inject/runtime/src/main/java/module-info.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * The Injection Runtime Services module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.runtime { - - requires io.helidon.builder.api; - requires io.helidon.common.config; - requires io.helidon.common; - requires io.helidon; - - requires static io.helidon.config.metadata; - requires static jakarta.annotation; - requires static jakarta.inject; - - requires transitive io.helidon.common.types;// required for compilation of generated types - requires transitive io.helidon.inject.api; - - exports io.helidon.inject.runtime; - - provides io.helidon.inject.spi.InjectionServicesProvider - with io.helidon.inject.runtime.DefaultInjectionServicesProvider; - provides io.helidon.spi.HelidonStartupProvider - with io.helidon.inject.runtime.HelidonInjectionStartupProvider; - - uses io.helidon.inject.api.ModuleComponent; - uses io.helidon.inject.api.Application; - -} diff --git a/inject/runtime/src/test/java/io/helidon/inject/runtime/ControlBlueprint.java b/inject/runtime/src/test/java/io/helidon/inject/runtime/ControlBlueprint.java deleted file mode 100644 index 688258e5fe5..00000000000 --- a/inject/runtime/src/test/java/io/helidon/inject/runtime/ControlBlueprint.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -@Prototype.Blueprint -interface ControlBlueprint { - Optional exceptionBeforeProceed(); - Optional exceptionAfterProceed(); - Optional shortCircuitValue(); - @ConfiguredOption("0") - int timesToCatchException(); - @ConfiguredOption("1") - int timesToCallProceed(); -} diff --git a/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultActivationLogTest.java b/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultActivationLogTest.java deleted file mode 100644 index 7dd88ea18c8..00000000000 --- a/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultActivationLogTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.inject.api.ActivationLogEntry; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalPresent; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -class DefaultActivationLogTest { - - private static final System.Logger LOGGER = System.getLogger(DefaultActivationLogTest.class.getName()); - - @Test - void testRetainedLog() { - DefaultActivationLog log = DefaultActivationLog.createRetainedLog(LOGGER); - log.level(System.Logger.Level.INFO); - log.record(ActivationLogEntry.builder().build()); - - assertThat(log.toQuery(), optionalPresent()); - assertThat(log.toQuery().orElseThrow().fullActivationLog().size(), equalTo(1)); - assertThat(log.reset(true), equalTo(Boolean.TRUE)); - assertThat(log.reset(true), equalTo(Boolean.FALSE)); - } - - @Test - void unretainedLog() { - DefaultActivationLog log = DefaultActivationLog.createUnretainedLog(LOGGER); - log.level(System.Logger.Level.INFO); - log.record(ActivationLogEntry.builder().build()); - - assertThat(log.toQuery(), optionalEmpty()); - } - -} diff --git a/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesConfigTest.java b/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesConfigTest.java deleted file mode 100644 index f002e2a5bc5..00000000000 --- a/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesConfigTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.inject.api.InjectionServicesConfig; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -class DefaultInjectionServicesConfigTest { - - @Test - void testIt() { - InjectionServicesConfig cfg = DefaultInjectionServicesConfig.createDefaultConfigBuilder() - .build(); - assertThat(cfg.providerName(), optionalValue(is("oracle"))); - assertThat(cfg.providerVersion(), optionalValue(is("1"))); - } - -} diff --git a/inject/runtime/src/test/java/io/helidon/inject/runtime/InvocationTest.java b/inject/runtime/src/test/java/io/helidon/inject/runtime/InvocationTest.java deleted file mode 100644 index 7db1b31e9f4..00000000000 --- a/inject/runtime/src/test/java/io/helidon/inject/runtime/InvocationTest.java +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; - -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypeValues; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.DeActivator; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.PostConstructMethod; -import io.helidon.inject.api.PreDestroyMethod; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderBindable; - -import jakarta.inject.Provider; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class InvocationTest { - TestInterceptor first; - TestInterceptor second; - InvocationContext dummyCtx; - ArrayList calls = new ArrayList<>(); - - @BeforeEach - void reset() { - first = new TestInterceptor("first"); - second = new TestInterceptor("second"); - dummyCtx = InvocationContext.builder() - .serviceProvider(new DummyServiceProvider()) - .serviceTypeName(TypeName.create(DummyServiceProvider.class)) - .elementInfo(TypedElementInfo.builder() - .elementName("test") - .elementTypeKind(TypeValues.KIND_METHOD) - .typeName(TypeName.create(InvocationTest.class))) - .interceptors(List.of(first.provider, second.provider)) - .build(); - calls.clear(); - } - @Test - void normalCaseWithInterceptors() { - Object[] args = new Object[] {}; - Boolean result = Invocation.createInvokeAndSupply(dummyCtx, (arguments) -> calls.add(arguments), args); - assertThat(result, is(true)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(1)); - assertThat(first.downstreamExceptionCount.get(), equalTo(0)); - assertThat(second.callCount.get(), equalTo(1)); - assertThat(second.proceedCount.get(), equalTo(1)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - } - - @Test - void normalCaseWithNoInterceptors() { - InvocationContext dummyCtx = InvocationContext.builder() - .serviceProvider(new DummyServiceProvider()) - .serviceTypeName(TypeName.create(DummyServiceProvider.class)) - .elementInfo(TypedElementInfo.builder() - .elementName("test") - .elementTypeKind(TypeValues.KIND_METHOD) - .typeName(TypeName.create(InvocationTest.class)) - .build()) - .interceptors(List.of()) - .build(); - - Object[] args = new Object[] {}; - Boolean result = Invocation.createInvokeAndSupply(dummyCtx, (arguments) -> calls.add(arguments), args); - assertThat(result, is(true)); - assertThat(first.callCount.get(), equalTo(0)); - assertThat(first.proceedCount.get(), equalTo(0)); - assertThat(first.downstreamExceptionCount.get(), equalTo(0)); - assertThat(second.callCount.get(), equalTo(0)); - assertThat(second.proceedCount.get(), equalTo(0)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - - calls.clear(); - RuntimeException re = new RuntimeException("forced"); - Function fnc = (arguments) -> { - throw re; - }; - InvocationException e = assertThrows(InvocationException.class, - () -> Invocation.createInvokeAndSupply(dummyCtx, fnc, args)); - assertThat(e.getMessage(), equalTo("Error in interceptor chain processing")); - assertThat(e.targetWasCalled(), is(true)); - assertThat(e.getCause(), is(re)); - assertThat(calls.size(), equalTo(0)); - } - - @Test - void illegalCallToInterceptorProceedTwice() { - first.control.timesToCallProceed(2); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - InvocationException e = assertThrows(InvocationException.class, - () -> Invocation.createInvokeAndSupply(dummyCtx, fnc, args)); - assertThat(e.getMessage(), - equalTo("Duplicate invocation, or unknown call type: io.helidon.inject.runtime.InvocationTest test")); - assertThat(e.targetWasCalled(), is(true)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(2)); - assertThat(first.downstreamExceptionCount.get(), equalTo(1)); - assertThat(second.callCount.get(), equalTo(1)); - assertThat(second.proceedCount.get(), equalTo(1)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - } - - @Test - void illegalCallToTargetProceedTwice() { - second.control.timesToCallProceed(2); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - InvocationException e = assertThrows(InvocationException.class, - () -> Invocation.createInvokeAndSupply(dummyCtx, fnc, args)); - assertThat(e.getMessage(), - equalTo("Duplicate invocation, or unknown call type: io.helidon.inject.runtime.InvocationTest test")); - assertThat(e.targetWasCalled(), is(true)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(1)); - assertThat(first.downstreamExceptionCount.get(), equalTo(1)); - assertThat(second.callCount.get(), equalTo(1)); - assertThat(second.proceedCount.get(), equalTo(2)); - assertThat(second.downstreamExceptionCount.get(), equalTo(1)); - assertThat(calls.size(), equalTo(1)); - } - - @Test - void illegalCallToProceedAfterSuccessfulCallToTargetButExceptionInInterceptor() { - first.control.timesToCallProceed(2).timesToCatchException(1); - second.control.exceptionAfterProceed(new RuntimeException("after")); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - InvocationException e = assertThrows(InvocationException.class, - () -> Invocation.createInvokeAndSupply(dummyCtx, fnc, args)); - assertThat(e.targetWasCalled(), is(true)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(2)); - assertThat(first.downstreamExceptionCount.get(), equalTo(2)); - assertThat(second.callCount.get(), equalTo(1)); - assertThat(second.proceedCount.get(), equalTo(1)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - } - - @Test - @Disabled - void exceptionThrownInInterceptorPriorToReachingTarget() { - first.control.timesToCatchException(1).timesToCallProceed(2); - second.control.exceptionBeforeProceed(new RuntimeException("before")); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - Boolean result = Invocation.createInvokeAndSupply(dummyCtx, fnc, args); - assertThat(result, is(true)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(2)); - assertThat(first.downstreamExceptionCount.get(), equalTo(1)); - assertThat(second.callCount.get(), equalTo(2)); - assertThat(second.proceedCount.get(), equalTo(1)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - } - - @Test - void exceptionThrownInInterceptorAfterReachingTarget() { - first.control.timesToCatchException(1).timesToCallProceed(2); - second.control.exceptionAfterProceed(new RuntimeException("after")); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - InvocationException e = assertThrows(InvocationException.class, - () -> Invocation.createInvokeAndSupply(dummyCtx, fnc, args)); - assertThat(e.getMessage(), - equalTo("Duplicate invocation, or unknown call type: io.helidon.inject.runtime.InvocationTest test")); - assertThat(e.targetWasCalled(), is(true)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(2)); - assertThat(first.downstreamExceptionCount.get(), equalTo(2)); - assertThat(second.callCount.get(), equalTo(1)); - assertThat(second.proceedCount.get(), equalTo(1)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - } - - @Test - @Disabled - void exceptionThrownMultipleTimesInSecond() { - first.control.timesToCatchException(3).timesToCallProceed(3); - second.control.exceptionBeforeProceed(new RuntimeException("before")); - second.control.exceptionAfterProceed(new RuntimeException("after")); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - Boolean result = Invocation.createInvokeAndSupply(dummyCtx, fnc, args); - assertThat("because exception happened after we called proceed in second the value is lost", result, nullValue()); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(3)); - assertThat(first.downstreamExceptionCount.get(), equalTo(3)); - assertThat(second.callCount.get(), equalTo(2)); - assertThat(second.proceedCount.get(), equalTo(1)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - } - - @Test - void shortCircuitInFirst() { - first.control.shortCircuitValue(false); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - Boolean result = Invocation.createInvokeAndSupply(dummyCtx, fnc, args); - assertThat(result, is(false)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(0)); - assertThat(first.downstreamExceptionCount.get(), equalTo(0)); - assertThat(second.callCount.get(), equalTo(0)); - assertThat(second.proceedCount.get(), equalTo(0)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(0)); - } - - @Test - void shortCircuitInSecond() { - second.control.shortCircuitValue(false); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - Boolean result = Invocation.createInvokeAndSupply(dummyCtx, fnc, args); - assertThat(result, is(false)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(1)); - assertThat(first.downstreamExceptionCount.get(), equalTo(0)); - assertThat(second.callCount.get(), equalTo(1)); - assertThat(second.proceedCount.get(), equalTo(0)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(0)); - } - - @Test - void firstDoingAllOfTheProceedCalls() { - first.control.timesToCallProceed(2); - second.control.timesToCallProceed(0); - Object[] args = new Object[] {}; - Function fnc = (arguments) -> calls.add(arguments); - Boolean result = Invocation.createInvokeAndSupply(dummyCtx, fnc, args); - assertThat(result, is(true)); - assertThat(first.callCount.get(), equalTo(1)); - assertThat(first.proceedCount.get(), equalTo(2)); - assertThat(first.downstreamExceptionCount.get(), equalTo(0)); - assertThat(second.callCount.get(), equalTo(1)); - assertThat(second.proceedCount.get(), equalTo(0)); - assertThat(second.downstreamExceptionCount.get(), equalTo(0)); - assertThat(calls.size(), equalTo(1)); - } - - static class ConcreteProvider implements Provider { - private final T delegate; - - ConcreteProvider(T delegate) { - this.delegate = delegate; - } - - @Override - public T get() { - return delegate; - } - - @Override - public String toString() { - return delegate.toString(); - } - } - - static class TestInterceptor { - final String name; - AtomicInteger callCount = new AtomicInteger(); - AtomicInteger proceedCount = new AtomicInteger(); - AtomicInteger downstreamExceptionCount = new AtomicInteger(); - Control.Builder control = Control.builder(); - ConcreteProvider provider = new ConcreteProvider<>(new Interceptor() { - @Override - public V proceed(InvocationContext ctx, Chain chain, Object... args) { - callCount.incrementAndGet(); - - RuntimeException re = control.exceptionBeforeProceed().orElse(null); - if (re != null) { - control.exceptionBeforeProceed(Optional.empty()); - throw re; - } - - if (control.shortCircuitValue().isPresent()) { - return (V) control.shortCircuitValue().get(); - } - - V v = null; - int countDown = control.timesToCallProceed(); - while (countDown-- > 0) { - proceedCount.incrementAndGet(); - - try { - v = chain.proceed(args); - } catch (RuntimeException e) { - downstreamExceptionCount.incrementAndGet(); - if (control.timesToCatchException() <= 0) { - throw e; - } - control.timesToCatchException(control.timesToCatchException() - 1); - } - - re = control.exceptionAfterProceed().orElse(null); - if (re != null) { - control.exceptionAfterProceed(Optional.empty()); - throw re; - } - } - - return v; - } - }); - - TestInterceptor(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } - } - - private static class DummyServiceProvider implements ServiceProvider { - - @Override - public Optional first(ContextualServiceQuery query) { - return Optional.empty(); - } - - @Override - public String id() { - return null; - } - - @Override - public String description() { - return null; - } - - @Override - public boolean isProvider() { - return false; - } - - @Override - public ServiceInfo serviceInfo() { - return null; - } - - @Override - public DependenciesInfo dependencies() { - return null; - } - - @Override - public Phase currentActivationPhase() { - return null; - } - - @Override - public Optional activator() { - return Optional.empty(); - } - - @Override - public Optional deActivator() { - return Optional.empty(); - } - - @Override - public Optional postConstructMethod() { - return Optional.empty(); - } - - @Override - public Optional preDestroyMethod() { - return Optional.empty(); - } - - @Override - public Optional> serviceProviderBindable() { - return Optional.empty(); - } - - @Override - public Class serviceType() { - return null; - } - } -} diff --git a/inject/runtime/src/test/java/io/helidon/inject/runtime/SimpleInjectionTestingSupport.java b/inject/runtime/src/test/java/io/helidon/inject/runtime/SimpleInjectionTestingSupport.java deleted file mode 100644 index 3ec647cc304..00000000000 --- a/inject/runtime/src/test/java/io/helidon/inject/runtime/SimpleInjectionTestingSupport.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.inject.api.InjectionServicesHolder; - -/** - * Supporting helper utilities unit-testing Injection services. - */ -class SimpleInjectionTestingSupport { - - /** - * Resets all internal Injection configuration instances, JVM global singletons, service registries, etc. - */ - static void resetAll() { - Holder.reset(); - } - - - @SuppressWarnings("deprecation") - private static class Holder extends InjectionServicesHolder { - public static void reset() { - InjectionServicesHolder.reset(); - } - } - -} diff --git a/inject/testing/pom.xml b/inject/testing/pom.xml deleted file mode 100644 index 726bfca8593..00000000000 --- a/inject/testing/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-testing - Helidon Injection Testing Support - - - - io.helidon.builder - helidon-builder-api - - - io.helidon.config - helidon-config - - - io.helidon.inject - helidon-inject-runtime - - - jakarta.inject - jakarta.inject-api - provided - - - io.helidon.common.testing - helidon-common-testing-junit5 - - - org.junit.jupiter - junit-jupiter-api - - - org.hamcrest - hamcrest-all - - - - diff --git a/inject/testing/src/main/java/io/helidon/inject/testing/InjectionTestingSupport.java b/inject/testing/src/main/java/io/helidon/inject/testing/InjectionTestingSupport.java deleted file mode 100644 index d254ea0795a..00000000000 --- a/inject/testing/src/main/java/io/helidon/inject/testing/InjectionTestingSupport.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.testing; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import io.helidon.common.LazyValue; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesConfig; -import io.helidon.inject.api.InjectionServicesHolder; -import io.helidon.inject.api.ServiceBinder; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.runtime.ServiceBinderDefault; - -/** - * Supporting helper utilities unit-testing Injection Services. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class InjectionTestingSupport { - private static LazyValue instance = lazyCreate(basicTestableConfig()); - - private InjectionTestingSupport() { - } - - /** - * Resets all internal configuration instances, JVM global singletons, service registries, etc. - */ - public static void resetAll() { - Internal.reset(); - } - - /** - * Provides a means to bind a service provider into the {@link Services} registry. - * - * @param injectionServices the services instance to bind into - * @param serviceProvider the service provider to bind - * @see ServiceBinder - */ - public static void bind(InjectionServices injectionServices, - ServiceProvider serviceProvider) { - ServiceBinderDefault binder = ServiceBinderDefault.create(injectionServices, InjectionTestingSupport.class.getSimpleName(), true); - binder.bind(serviceProvider); - } - - /** - * Creates a {@link InjectionServices} interface more conducive to unit and integration testing. - * - * @return testable services instance - */ - public static InjectionServices testableServices() { - return instance.get(); - } - - /** - * Creates a {@link InjectionServices} interface more conducive to unit and integration testing. - * - * @param config the config to use - * @return testable services instance - * @see InjectionServicesConfig - */ - public static InjectionServices testableServices(Config config) { - return lazyCreate(config).get(); - } - - /** - * Basic testable configuration. - * - * @return testable config - */ - public static Config basicTestableConfig() { - return Config.builder( - ConfigSources.create( - Map.of("inject.permits-dynamic", "true", - "inject.service-lookup-caching", "true"), - "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - } - - /** - * Describe the provided instance or provider. - * - * @param providerOrInstance the instance to provider - * @return the description of the instance - */ - public static String toDescription(Object providerOrInstance) { - if (providerOrInstance instanceof Optional) { - providerOrInstance = ((Optional) providerOrInstance).orElse(null); - } - - if (providerOrInstance instanceof ServiceProvider) { - return ((ServiceProvider) providerOrInstance).description(); - } - return String.valueOf(providerOrInstance); - } - - /** - * Describe the provided instance or provider collection. - * - * @param coll the instance to provider collection - * @return the description of the instance - */ - public static List toDescriptions(Collection coll) { - return coll.stream().map(InjectionTestingSupport::toDescription).collect(Collectors.toList()); - } - - private static LazyValue lazyCreate(Config config) { - return LazyValue.create(() -> { - InjectionServices.globalBootstrap(Bootstrap.builder().config(config).build()); - return InjectionServices.injectionServices().orElseThrow(); - }); - } - - @SuppressWarnings("deprecation") - private static class Internal extends InjectionServicesHolder { - public static void reset() { - InjectionServicesHolder.reset(); - instance = lazyCreate(basicTestableConfig()); - } - } - -} diff --git a/inject/testing/src/main/java/io/helidon/inject/testing/ReflectionBasedSingletonServiceProvider.java b/inject/testing/src/main/java/io/helidon/inject/testing/ReflectionBasedSingletonServiceProvider.java deleted file mode 100644 index 508da0b729d..00000000000 --- a/inject/testing/src/main/java/io/helidon/inject/testing/ReflectionBasedSingletonServiceProvider.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.testing; - -import java.lang.reflect.Constructor; -import java.util.Map; -import java.util.Objects; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.PostConstructMethod; -import io.helidon.inject.api.PreDestroyMethod; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.ServiceProviderInjectionException; -import io.helidon.inject.runtime.AbstractServiceProvider; - -/** - * Creates a simple reflection based service provider - for testing purposes only! - * - * @param the service type - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class ReflectionBasedSingletonServiceProvider extends AbstractServiceProvider { - private final Class serviceType; - - private ReflectionBasedSingletonServiceProvider(Class serviceType, - ServiceInfo serviceInfo) { - this.serviceType = serviceType; - serviceInfo(serviceInfo); - } - - /** - * Generates a service provider eligible for binding into the service registry with the following proviso: - *
    - *
  • The service type will be of {@code jakarta.inject.Singleton} scope
  • - *
  • The service type will be created reflectively, and will expect to have an empty constructor
  • - *
  • The service type will not be able to provide its dependencies, nor will it be able to accept injection
  • - *
  • The service type will not be able to participate in lifecycle - - * {@link PostConstructMethod} or {@link PreDestroyMethod}
  • - *
- * Note: Generally it is encouraged for users to rely on the annotation processors and other built on compile-time - * tooling to generate the appropriate service providers and modules. This method is an alternative to that - * mechanism and therefore is discouraged from production use. This method is not used in normal processing by - * the reference injection provider implementation. - * - * @param serviceType the service type - * @param siBasics the service info basic descriptor, or null to generate a default (empty) placeholder - * @param the class of the service type - * - * @return the service provider capable of being bound to the services registry - * @see InjectionTestingSupport#bind(InjectionServices, ServiceProvider) - */ - public static ReflectionBasedSingletonServiceProvider create(Class serviceType, - ServiceInfoBasics siBasics) { - Objects.requireNonNull(serviceType); - Objects.requireNonNull(siBasics); - - if (!TypeName.create(serviceType).equals(siBasics.serviceTypeName())) { - throw new IllegalArgumentException("Mismatch in service types: " + serviceType.getName()); - } - - return new ReflectionBasedSingletonServiceProvider<>(serviceType, ServiceInfo.builder(siBasics).build()); - } - - @Override - public boolean isCustom() { - return true; - } - - @Override - protected T createServiceProvider(Map deps) { - try { - Constructor ctor = serviceType.getDeclaredConstructor(); - ctor.setAccessible(true); - return ctor.newInstance(); - } catch (Exception e) { - throw new ServiceProviderInjectionException("Failed to fully create instance: " + this, e, this); - } - } - - @Override - public Class serviceType() { - return serviceType; - } -} diff --git a/inject/testing/src/main/java/io/helidon/inject/testing/package-info.java b/inject/testing/src/main/java/io/helidon/inject/testing/package-info.java deleted file mode 100644 index e8bb2058ebf..00000000000 --- a/inject/testing/src/main/java/io/helidon/inject/testing/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection testing support. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -package io.helidon.inject.testing; diff --git a/inject/testing/src/main/java/module-info.java b/inject/testing/src/main/java/module-info.java deleted file mode 100644 index 9f1aaec097d..00000000000 --- a/inject/testing/src/main/java/module-info.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Testing Support module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.testing { - - requires io.helidon.builder.api; - requires io.helidon.common.types; - requires io.helidon.config; - - requires transitive io.helidon.inject.runtime; - - exports io.helidon.inject.testing; - -} diff --git a/inject/tests/api/pom.xml b/inject/tests/api/pom.xml deleted file mode 100644 index 2c439b4c2c3..00000000000 --- a/inject/tests/api/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - io.helidon.inject.tests - helidon-inject-tests-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-tests-api - Helidon Injection Tests API - - Test Injection API to remove dependency on Helidon Config, which did not allow us to have contracts in config. - - - - - io.helidon.inject - helidon-inject-api - - - io.helidon.config - helidon-config - test - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - diff --git a/inject/tests/api/src/test/java/io/helidon/inject/api/InjectionServicesConfigTest.java b/inject/tests/api/src/test/java/io/helidon/inject/api/InjectionServicesConfigTest.java deleted file mode 100644 index f0ba5f110d8..00000000000 --- a/inject/tests/api/src/test/java/io/helidon/inject/api/InjectionServicesConfigTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.api; - -import java.time.Duration; -import java.util.Map; - -import io.helidon.common.config.Config; -import io.helidon.config.ConfigSources; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalPresent; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -class InjectionServicesConfigTest { - - @AfterEach - void reset() { - InjectionServicesHolder.reset(); - } - - /** - * This tests the default injection configuration. - */ - @Test - void withOutBootstrap() { - InjectionServicesConfig cfg = InjectionServicesConfig.create(); - assertThat(cfg.serviceLookupCaching(), equalTo(Boolean.FALSE)); - assertThat(cfg.activationLogs(), equalTo(Boolean.FALSE)); - assertThat(cfg.activationDeadlockDetectionTimeout(), equalTo(Duration.ofSeconds(10))); - assertThat(cfg.permitsDynamic(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsDynamic(), equalTo(Boolean.TRUE)); - assertThat(cfg.permitsReflection(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsReflection(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsJsr330(), equalTo(Boolean.TRUE)); - assertThat(cfg.supportsJsr330Statics(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsJsr330Privates(), equalTo(Boolean.FALSE)); - assertThat(cfg.usesJsr330(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsCompileTime(), equalTo(Boolean.TRUE)); - assertThat(cfg.usesCompileTimeApplications(), equalTo(Boolean.TRUE)); - assertThat(cfg.usesCompileTimeModules(), equalTo(Boolean.TRUE)); - assertThat(cfg.supportsContextualLookup(), equalTo(Boolean.FALSE)); - assertThat(cfg.providerName(), optionalEmpty()); - assertThat(cfg.providerVersion(), optionalEmpty()); - } - - @Test - void withBootstrapWithoutConfig() { - Bootstrap bootstrap = Bootstrap.builder().build(); - InjectionServicesHolder.bootstrap(bootstrap); - assertThat(InjectionServicesHolder.bootstrap(false), optionalPresent()); - - // should be the same as if we had no bootstrap - withOutBootstrap(); - } - - @Test - void withBootStrapConfig() { - Config config = io.helidon.config.Config.builder( - ConfigSources.create( - Map.of("inject.provider-name", "fake", - "inject.provider-version", "2.4", - "inject.service-lookup-caching", "true", - "inject.activation-logs", "true", - "inject.activation-deadlock-detection-timeout", "PT0.111S", - "inject.permits-dynamic", "true", - "inject.permits-reflection", "true", - "inject.uses-jsr330", "true", - "inject.uses-compile-time-applications", "false", - "inject.uses-compile-time-modules", "false" - ), "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - Bootstrap bootstrap = Bootstrap.builder() - .config(config) - .build(); - InjectionServicesHolder.bootstrap(bootstrap); - assertThat(InjectionServicesHolder.bootstrap(false), optionalPresent()); - - InjectionServicesConfig cfg = InjectionServicesConfig.create(config.get("inject")); - assertThat(cfg.serviceLookupCaching(), equalTo(Boolean.TRUE)); - assertThat(cfg.activationLogs(), equalTo(Boolean.TRUE)); - assertThat(cfg.activationDeadlockDetectionTimeout(), equalTo(Duration.ofMillis(111))); - assertThat(cfg.permitsDynamic(), equalTo(Boolean.TRUE)); - assertThat(cfg.supportsDynamic(), equalTo(Boolean.TRUE)); - assertThat(cfg.permitsReflection(), equalTo(Boolean.TRUE)); - assertThat(cfg.supportsReflection(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsJsr330(), equalTo(Boolean.TRUE)); - assertThat(cfg.supportsJsr330Statics(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsJsr330Privates(), equalTo(Boolean.FALSE)); - assertThat(cfg.usesJsr330(), equalTo(Boolean.TRUE)); - assertThat(cfg.supportsCompileTime(), equalTo(Boolean.TRUE)); - assertThat(cfg.usesCompileTimeApplications(), equalTo(Boolean.FALSE)); - assertThat(cfg.usesCompileTimeModules(), equalTo(Boolean.FALSE)); - assertThat(cfg.supportsContextualLookup(), equalTo(Boolean.FALSE)); - assertThat(cfg.providerName(), optionalValue(is("fake"))); - assertThat(cfg.providerVersion(), optionalValue(is("2.4"))); - } - -} diff --git a/inject/tests/interception/pom.xml b/inject/tests/interception/pom.xml deleted file mode 100644 index 47a74dfcaa3..00000000000 --- a/inject/tests/interception/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - io.helidon.inject.tests - helidon-inject-tests-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-tests-interception - Helidon Injection Test Interception - Test interception. - - - - io.helidon.inject - helidon-inject-processor - - true - - - jakarta.inject - jakarta.inject-api - provided - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.inject - helidon-inject-runtime - - - org.junit.jupiter - junit-jupiter-api - test - - - org.hamcrest - hamcrest-all - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - - -Ainject.acceptPreview=true - - - - io.helidon.inject - helidon-inject-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - - - diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Invocation.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Invocation.java deleted file mode 100644 index e957b04242f..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Invocation.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import java.util.Arrays; - -record Invocation(String methodName, Object[] args) { - @Override - public String toString() { - return methodName + "(" + Arrays.toString(args) + ")"; - } -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Modify.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Modify.java deleted file mode 100644 index 81ff657d9d5..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Modify.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import io.helidon.inject.api.InterceptedTrigger; - -/** - * Modify call. - */ -@Retention(RetentionPolicy.RUNTIME) -@Documented -@InterceptedTrigger -@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) -@interface Modify { -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/ModifyingInterceptor.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/ModifyingInterceptor.java deleted file mode 100644 index 811e6094943..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/ModifyingInterceptor.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationContext; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Named("io.helidon.inject.tests.interception.Modify") -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT + 50) -class ModifyingInterceptor implements Interceptor { - private static final AtomicReference LAST_CALL = new AtomicReference<>(); - - static Invocation lastCall() { - return LAST_CALL.getAndSet(null); - } - - @Override - public V proceed(InvocationContext ctx, Chain chain, Object... args) { - LAST_CALL.set(new Invocation(ctx.elementInfo().elementName(), Arrays.copyOf(args, args.length))); - if (args.length < 2) { - // safeguard - return chain.proceed(args); - } - System.out.println("Modify"); - // args: - // 0: String message - // 1: Boolean modify - // 2: Boolean repeat - // 3: Boolean return - if ((Boolean) args[1]) { - args[0] = "mod_" + args[0]; - } - return chain.proceed(args); - } -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/OtherContract.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/OtherContract.java deleted file mode 100644 index 1d7dcf69b05..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/OtherContract.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import io.helidon.inject.api.Contract; - -@Contract -interface OtherContract { - @Modify - @Repeat - @Return - String intercepted(String message, boolean modify, boolean repeat, boolean doReturn); - - @Return - String interceptedSubset(String message, boolean modify, boolean repeat, boolean doReturn); - - String notIntercepted(String message, boolean modify, boolean repeat, boolean doReturn); - - void throwException(boolean throwException); - -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Repeat.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Repeat.java deleted file mode 100644 index fbd8c1d356c..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Repeat.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import io.helidon.inject.api.InterceptedTrigger; - -/** - * Repeat the call twice. - */ -@Retention(RetentionPolicy.RUNTIME) -@Documented -@InterceptedTrigger -@Target(ElementType.METHOD) -@interface Repeat { - -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/RepeatingInterceptor.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/RepeatingInterceptor.java deleted file mode 100644 index 506b1e3c3ae..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/RepeatingInterceptor.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.InvocationException; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Named("io.helidon.inject.tests.interception.Repeat") -@Singleton -class RepeatingInterceptor implements Interceptor { - private static final AtomicReference LAST_CALL = new AtomicReference<>(); - - static Invocation lastCall() { - return LAST_CALL.getAndSet(null); - } - - @Override - public V proceed(InvocationContext ctx, Chain chain, Object... args) { - LAST_CALL.set(new Invocation(ctx.elementInfo().elementName(), Arrays.copyOf(args, args.length))); - if (args.length < 3) { - // safeguard - return chain.proceed(args); - } - System.out.println("Repeat"); - // args: - // 0: String message - // 1: Boolean modify - // 2: Boolean repeat - // 3: Boolean return - if ((Boolean) args[2]) { - try { - chain.proceed(args); - } catch (Exception e) { - System.out.println("exception 1: " + e.getClass().getName() + ": " + e.getMessage()); - } - } - try { - return chain.proceed(args); - } catch (InvocationException e) { - throw e; - } catch (Exception e) { - System.out.println("exception 2: " + e.getClass().getName() + ": " + e.getMessage()); - return null; - } - } -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Return.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Return.java deleted file mode 100644 index 623d5a70b15..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/Return.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import io.helidon.inject.api.InterceptedTrigger; - -/** - * Return an explicit value (do not call target). - */ -@Retention(RetentionPolicy.RUNTIME) -@Documented -@InterceptedTrigger -@Target(ElementType.METHOD) -@interface Return { - -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/ReturningInterceptor.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/ReturningInterceptor.java deleted file mode 100644 index c338f0b1436..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/ReturningInterceptor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationContext; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Named("io.helidon.inject.tests.interception.Return") -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT + 100) -class ReturningInterceptor implements Interceptor { - private static final AtomicReference LAST_CALL = new AtomicReference<>(); - - static Invocation lastCall() { - return LAST_CALL.getAndSet(null); - } - - @SuppressWarnings("unchecked") - @Override - public V proceed(InvocationContext ctx, Chain chain, Object... args) { - LAST_CALL.set(new Invocation(ctx.elementInfo().elementName(), Arrays.copyOf(args, args.length))); - if (args.length < 4) { - // safeguard - return chain.proceed(args); - } - System.out.println("Return"); - // args: - // 0: String message - // 1: Boolean modify - // 2: Boolean repeat - // 3: Boolean return - if ((Boolean) args[3]) { - return (V) "fixed_answer"; - } - return chain.proceed(args); - } -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/TheOtherService.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/TheOtherService.java deleted file mode 100644 index ef8a0279756..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/TheOtherService.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import jakarta.inject.Singleton; - -@Singleton -class TheOtherService implements OtherContract { - private boolean throwException; - - @Modify - TheOtherService() { - } - - @Override - public void throwException(boolean throwException) { - this.throwException = throwException; - } - - @Override - public String intercepted(String message, boolean modify, boolean repeat, boolean doReturn) { - if (throwException) { - throwException = false; - throw new RuntimeException("forced"); - } - - return message; - } - - // one interceptor on interface, one on implementation - @Repeat - @Override - public String interceptedSubset(String message, boolean modify, boolean repeat, boolean doReturn) { - if (throwException) { - throwException = false; - throw new RuntimeException("forced"); - } - - return message; - } - - @Override - public String notIntercepted(String message, boolean modify, boolean repeat, boolean doReturn) { - if (throwException) { - throwException = false; - throw new RuntimeException("forced"); - } - - return message; - } - -} diff --git a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/TheService.java b/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/TheService.java deleted file mode 100644 index 73be46434be..00000000000 --- a/inject/tests/interception/src/main/java/io/helidon/inject/tests/interception/TheService.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import jakarta.inject.Singleton; - -@Singleton -class TheService { - private boolean throwException; - - @Modify - TheService() { - } - - void throwException(boolean throwException) { - this.throwException = throwException; - } - - // args: - // 0: String message - // 1: Boolean modify - // 2: Boolean repeat - // 3: Boolean return - @Modify - @Repeat - @Return - String intercepted(String message, boolean modify, boolean repeat, boolean doReturn) { - if (throwException) { - throwException = false; - throw new RuntimeException("forced"); - } - - return message; - } - - @Repeat - @Return - String interceptedSubset(String message, boolean modify, boolean repeat, boolean doReturn) { - if (throwException) { - throwException = false; - throw new RuntimeException("forced"); - } - - return message; - } - - String notIntercepted(String message, boolean modify, boolean repeat, boolean doReturn) { - if (throwException) { - throwException = false; - throw new RuntimeException("forced"); - } - - return message; - } - -} diff --git a/inject/tests/interception/src/test/java/io/helidon/inject/tests/interception/InterceptionTest.java b/inject/tests/interception/src/test/java/io/helidon/inject/tests/interception/InterceptionTest.java deleted file mode 100644 index 216629abda1..00000000000 --- a/inject/tests/interception/src/test/java/io/helidon/inject/tests/interception/InterceptionTest.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Services; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/* -Order of interceptors: -Returning -Modifying -Repeating - */ -class InterceptionTest { - private static InjectionServices injectionServices; - private static Services services; - private static TheService service; - - @BeforeAll - static void init() { - injectionServices = InjectionServices.injectionServices().orElseThrow(); - services = injectionServices.services(); - service = services.lookup(TheService.class).get(); - - assertAll( - () -> assertThat("Interceptors should not be called for constructor - returning", - ReturningInterceptor.lastCall(), - nullValue()), - () -> assertThat("Interceptors should be called for constructor - modifying", - ModifyingInterceptor.lastCall(), - notNullValue()), - () -> assertThat("Interceptors should not be called for constructor - repeating", - RepeatingInterceptor.lastCall(), - nullValue()) - ); - } - - @BeforeEach - void beforeEach() { - // cleanup possible last calls from failed tests - ReturningInterceptor.lastCall(); - ModifyingInterceptor.lastCall(); - RepeatingInterceptor.lastCall(); - service.throwException(false); - } - - @Test - void testNotIntercepted() { - String response = service.notIntercepted("hello", true, true, true); - - assertAll( - () -> assertThat("Interceptors should not be called for method not annotated", - ReturningInterceptor.lastCall(), - nullValue()), - () -> assertThat("Interceptors should not be called for method not annotated", - ModifyingInterceptor.lastCall(), - nullValue()), - () -> assertThat("Interceptors should not be called for method not annotated", - RepeatingInterceptor.lastCall(), - nullValue()) - ); - - assertThat(response, is("hello")); - } - - @Test - void testInterceptedSubset() { - // test that only the interceptors valid for annotations are invoked - String response = service.interceptedSubset("hello", true, false, false); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - - // first make sure the interceptors were/were not called - assertAll( - () -> assertThat("Interceptors should not be called for method not annotated with @Modify", - modifying, - nullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Repeat", - repeating, - notNullValue()) - ); - - // then assert the called values - assertAll( - () -> assertThat("Returning last call", returning.methodName(), is("interceptedSubset")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", true, false, false})), - () -> assertThat("Repeating last call", repeating.methodName(), is("interceptedSubset")), - () -> assertThat("Repeating last call", repeating.args(), is(new Object[] {"hello", true, false, false})) - ); - - // and finally the response string - assertThat(response, is("hello")); - } - - @Test - void testReturn() { - String response = service.intercepted("hello", false, false, true); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - // first make sure the interceptors were/were not called - assertAll( - () -> assertThat("Interceptors should not be called as ReturningInterceptor should have returned", - modifying, - nullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - () -> assertThat("Interceptor should not be called as ReturningInterceptor should have returned", - repeating, - nullValue()) - ); - - assertAll( - () -> assertThat("Returning last call", returning.methodName(), is("intercepted")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", false, false, true})) - ); - - assertThat(response, is("fixed_answer")); - } - - @Test - void testModify() { - String response = service.intercepted("hello", true, false, false); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - - // first make sure the interceptors were/were not called - assertAll( - () -> assertThat("Interceptors should be called for method annotated with @Modify", - modifying, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Repeat", - repeating, - notNullValue()) - ); - - // then assert the called values - assertAll( - () -> assertThat("Returning last call", returning.methodName(), is("intercepted")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", true, false, false})), - () -> assertThat("Modifying last call", modifying.methodName(), is("intercepted")), - () -> assertThat("Modifying last call", modifying.args(), is(new Object[] {"hello", true, false, false})), - () -> assertThat("Repeating last call", repeating.methodName(), is("intercepted")), - () -> assertThat("Repeating last call", repeating.args(), is(new Object[] {"mod_hello", true, false, false})) - ); - - // and the message - assertThat(response, is("mod_hello")); - } - - /** - * Once the target is called once successfully it should not be allowed to repeat normally. - */ - @Test - void testRepeatWithNoExceptionThrownFromTarget() { - InvocationException e = assertThrows(InvocationException.class, - () -> service.intercepted("hello", false, true, false)); - assertThat(e.getMessage(), equalTo("Duplicate invocation, or unknown call type: java.lang.String intercepted")); - assertThat(e.targetWasCalled(), is(true)); - } - - @Test - void testRepeatWithExceptionThrownFromTarget() { - service.throwException(true); - - String response = service.intercepted("hello", false, true, false); - assertThat(response, equalTo("hello")); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - - // first make sure the interceptors were/were not called - assertAll( - () -> assertThat("Interceptors should be called for method annotated with @Modify", - modifying, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Repeat", - repeating, - notNullValue()) - ); - - // then assert the called values - assertAll( - () -> assertThat("Returning last call", returning.methodName(), is("intercepted")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", false, true, false})), - () -> assertThat("Modifying last call", modifying.methodName(), is("intercepted")), - () -> assertThat("Modifying last call", modifying.args(), is(new Object[] {"hello", false, true, false})), - () -> assertThat("Repeating last call", repeating.methodName(), is("intercepted")), - () -> assertThat("Repeating last call", repeating.args(), is(new Object[] {"hello", false, true, false})) - ); - } - -} diff --git a/inject/tests/interception/src/test/java/io/helidon/inject/tests/interception/InterfaceInterceptionTest.java b/inject/tests/interception/src/test/java/io/helidon/inject/tests/interception/InterfaceInterceptionTest.java deleted file mode 100644 index 31d5a2300b8..00000000000 --- a/inject/tests/interception/src/test/java/io/helidon/inject/tests/interception/InterfaceInterceptionTest.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.interception; - -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.Services; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/* -Order of interceptors: -Returning -Modifying -Repeating - */ -class InterfaceInterceptionTest { - private static InjectionServices injectionServices; - private static Services services; - private static OtherContract service; - - @BeforeAll - static void init() { - injectionServices = InjectionServices.injectionServices().orElseThrow(); - services = injectionServices.services(); - service = services.lookup(OtherContract.class).get(); - - assertAll( - () -> assertThat("Interceptors should not be called for constructor - returning", - ReturningInterceptor.lastCall(), - nullValue()), - /* Does not work, issue #6647 - () -> assertThat("Interceptors should be called for constructor - modifying", - ModifyingInterceptor.lastCall(), - notNullValue()), - */ - () -> assertThat("Interceptors should not be called for constructor - repeating", - RepeatingInterceptor.lastCall(), - nullValue()) - ); - } - - @BeforeEach - void beforeEach() { - // cleanup possible last calls from failed tests - ReturningInterceptor.lastCall(); - ModifyingInterceptor.lastCall(); - RepeatingInterceptor.lastCall(); - } - - @Test - void testNotIntercepted() { - String response = service.notIntercepted("hello", true, true, true); - - assertAll( - () -> assertThat("Interceptors should not be called for method not annotated", - ReturningInterceptor.lastCall(), - nullValue()), - () -> assertThat("Interceptors should not be called for method not annotated", - ModifyingInterceptor.lastCall(), - nullValue()), - () -> assertThat("Interceptors should not be called for method not annotated", - RepeatingInterceptor.lastCall(), - nullValue()) - ); - - assertThat(response, is("hello")); - } - - @Test - void testInterceptedSubset() { - // test that only the interceptors valid for annotations are invoked - String response = service.interceptedSubset("hello", true, false, false); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - - // first make sure the interceptors were/were not called - assertAll( - () -> assertThat("Interceptors should not be called for method not annotated with @Modify", - modifying, - nullValue()), - /* Does not work, issue #6647 - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - */ - () -> assertThat("Interceptor should be called for method annotated with @Repeat", - repeating, - notNullValue()) - ); - - // then assert the called values - assertAll( - /* Does not work, issue #6647 - () -> assertThat("Returning last call", returning.methodName(), is("interceptedSubset")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", true, false, false})), - */ - () -> assertThat("Repeating last call", repeating.methodName(), is("interceptedSubset")), - () -> assertThat("Repeating last call", repeating.args(), is(new Object[] {"hello", true, false, false})) - ); - - // and finally the response string - assertThat(response, is("hello")); - } - - @Test - void testReturn() { - String response = service.intercepted("hello", false, false, true); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - // first make sure the interceptors were/were not called - assertAll( - () -> assertThat("Interceptors should not be called as ReturningInterceptor should have returned", - modifying, - nullValue()), - /* Does not work, issue #6647 - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - */ - () -> assertThat("Interceptor should not be called as ReturningInterceptor should have returned", - repeating, - nullValue()) - ); - - /* Does not work, issue #6647 - assertAll( - () -> assertThat("Returning last call", returning.methodName(), is("intercepted")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", false, false, true})) - ); - - assertThat(response, is("fixed_answer")); - */ - } - - @Test - void testModify() { - String response = service.intercepted("hello", true, false, false); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - - // first make sure the interceptors were/were not called - /* Does not work, issue #6647 - assertAll( - () -> assertThat("Interceptors should be called for method annotated with @Modify", - modifying, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Repeat", - repeating, - notNullValue()) - ); - - // then assert the called values - assertAll( - () -> assertThat("Returning last call", returning.methodName(), is("intercepted")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", true, false, false})), - () -> assertThat("Modifying last call", modifying.methodName(), is("intercepted")), - () -> assertThat("Modifying last call", modifying.args(), is(new Object[] {"hello", true, false, false})), - () -> assertThat("Repeating last call", repeating.methodName(), is("intercepted")), - () -> assertThat("Repeating last call", repeating.args(), is(new Object[] {"mod_hello", true, false, false})) - ); - - // and the message - assertThat(response, is("mod_hello")); - */ - } - - /** - * Once the target is called once successfully it should not be allowed to repeat normally. - */ - @Disabled("Known problem - issue #6647") - @Test - void testRepeatWithNoExceptionThrownFromTarget() { - InvocationException e = assertThrows(InvocationException.class, - () -> service.intercepted("hello", false, true, false)); - assertThat(e.getMessage(), equalTo("Duplicate invocation, or unknown call type: java.lang.String intercepted")); - assertThat(e.targetWasCalled(), is(true)); - } - - @Disabled("Known problem - issue #6647") - @Test - void testRepeatWithExceptionThrownFromTarget() { - service.throwException(true); - - String response = service.intercepted("hello", false, true, false); - assertThat(response, equalTo("hello")); - - Invocation returning = ReturningInterceptor.lastCall(); - Invocation modifying = ModifyingInterceptor.lastCall(); - Invocation repeating = RepeatingInterceptor.lastCall(); - - // first make sure the interceptors were/were not called - assertAll( - () -> assertThat("Interceptors should be called for method annotated with @Modify", - modifying, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Return", - returning, - notNullValue()), - () -> assertThat("Interceptor should be called for method annotated with @Repeat", - repeating, - notNullValue()) - ); - - // then assert the called values - assertAll( - () -> assertThat("Returning last call", returning.methodName(), is("intercepted")), - () -> assertThat("Returning last call", returning.args(), is(new Object[] {"hello", false, true, false})), - () -> assertThat("Modifying last call", modifying.methodName(), is("intercepted")), - () -> assertThat("Modifying last call", modifying.args(), is(new Object[] {"hello", false, true, false})), - () -> assertThat("Repeating last call", repeating.methodName(), is("intercepted")), - () -> assertThat("Repeating last call", repeating.args(), is(new Object[] {"hello", false, true, false})) - ); - } - -} diff --git a/inject/tests/pom.xml b/inject/tests/pom.xml deleted file mode 100644 index 57ec8bb1a83..00000000000 --- a/inject/tests/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - 4.0.0 - - io.helidon.inject.tests - helidon-inject-tests-project - - Helidon Injection Tests Project - pom - - - true - true - true - true - true - true - true - - - - resources-plain - resources-inject - tck-jsr330 - interception - api - runtime - - - diff --git a/inject/tests/resources-inject/pom.xml b/inject/tests/resources-inject/pom.xml deleted file mode 100644 index 57af8862523..00000000000 --- a/inject/tests/resources-inject/pom.xml +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - io.helidon.inject.tests - helidon-inject-tests-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-tests-resources-inject - Helidon Injection Test Injectable Resources - a jar that offers contracts and other artifacts and is a native injection module (e.g., uses injection APT). - - - true - - - - - io.helidon.config - helidon-config - - - io.helidon.config - helidon-config-metadata - provided - - - io.helidon.inject - helidon-inject-maven-plugin - ${helidon.version} - provided - true - - - io.helidon.inject.tests - helidon-inject-tests-resources-plain - ${helidon.version} - - - jakarta.inject - jakarta.inject-api - provided - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.inject - helidon-inject-runtime - - - io.helidon.inject - helidon-inject-testing - test - - - jakarta.enterprise - jakarta.enterprise.cdi-api - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - -Ainject.autoAddNonContractInterfaces=true - -Ainject.allowListedInterceptorAnnotations=io.helidon.inject.tests.inject.interceptor.TestNamed - -Ainject.application.pre.create=false - -Ainject.mapApplicationToSingletonScope=true - -Ainject.debug=${inject.debug} - - - - -Ainject.acceptPreview=true - - true - - - io.helidon.inject - helidon-inject-processor - ${helidon.version} - - - jakarta.enterprise - jakarta.enterprise.cdi-api - ${version.lib.jakarta.cdi-api} - - - io.helidon.inject.tests - helidon-inject-tests-resources-plain - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - - io.helidon.inject - helidon-inject-processor - ${helidon.version} - - - io.helidon.common.processor - helidon-common-processor-helidon-copyright - ${helidon.version} - - - - - io.helidon.inject - helidon-inject-maven-plugin - ${helidon.version} - - - compile - compile - - application-create - - - - testCompile - test-compile - - test-application-create - - - - - - -Ainject.debug=${inject.debug} - -Ainject.autoAddNonContractInterfaces=true - -Ainject.application.pre.create=false - - NAMED - - io.helidon.inject.tests.inject.provider.MyServices$MyConcreteClassContractPerRequestIPProvider - io.helidon.inject.tests.inject.provider.MyServices$MyConcreteClassContractPerRequestProvider - io.helidon.inject.tests.inject.ASerialProviderImpl - io.helidon.inject.tests.inject.tbox.impl.BladeProvider - - - - - - - diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/AContractWithNoServiceImplementations.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/AContractWithNoServiceImplementations.java deleted file mode 100644 index abbaf9072b2..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/AContractWithNoServiceImplementations.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import io.helidon.inject.api.Contract; - -@Contract -interface AContractWithNoServiceImplementations { -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ASerialProviderImpl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ASerialProviderImpl.java deleted file mode 100644 index 0472470e8c2..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ASerialProviderImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import java.io.Serializable; -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; - -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -/** - * Testing. - */ -@Weight(Weighted.DEFAULT_WEIGHT + 100) -@Singleton -public class ASerialProviderImpl implements Provider { - - static { - System.getLogger(ASerialProviderImpl.class.getName()).log(System.Logger.Level.DEBUG, "in static init"); - } - - private final AtomicInteger counter = new AtomicInteger(); - - @Override - public Serializable get() { - return String.valueOf(counter.incrementAndGet()); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/AServiceUsingAContractWithNoServiceImplementations.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/AServiceUsingAContractWithNoServiceImplementations.java deleted file mode 100644 index dae6cca5372..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/AServiceUsingAContractWithNoServiceImplementations.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import java.util.List; - -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@Singleton -class AServiceUsingAContractWithNoServiceImplementations { - - @Inject - AServiceUsingAContractWithNoServiceImplementations(List> list) { - if (!list.isEmpty()) { - throw new AssertionError("Should be empty: " + list); - } - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ClassNamedY.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ClassNamedY.java deleted file mode 100644 index ada45374422..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ClassNamedY.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -/** - * For Testing. - */ -public class ClassNamedY { -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/SomeOtherLocalNonContractInterface1.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/SomeOtherLocalNonContractInterface1.java deleted file mode 100644 index 8ecc32c982d..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/SomeOtherLocalNonContractInterface1.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -/** - * Testing. - */ -public interface SomeOtherLocalNonContractInterface1 { - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/Verification.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/Verification.java deleted file mode 100644 index ccb5d23ec9b..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/Verification.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import jakarta.inject.Provider; - -/** - * Testing. - */ -public abstract class Verification { - - /** - * Testing. - * - * @param injectee injectee - * @param tag tag - * @param injectedCount injectedCount - * @param expected expected - * @param expectedType expectedType - */ - public static void verifyInjected(Optional injectee, - String tag, - Integer injectedCount, - boolean expected, - Class expectedType) { - if (expected && injectee.isEmpty()) { - throw new AssertionError(tag + " was expected to be present"); - } else if (!expected && injectee.isPresent()) { - throw new AssertionError(tag + " was not expected to be present"); - } - - if (expectedType != null && expected && !expectedType.isInstance(injectee.get())) { - throw new AssertionError(tag + " was expected to be of type " + expectedType + " : " + injectee); - } - - if (injectedCount != null && injectedCount != 1) { - throw new AssertionError(tag - + " was was expected to be injected 1 time; it was actually injected " + injectedCount + " times"); - } - } - - /** - * Testing. - * - * @param injectee injectee - * @param tag tag - * @param injectedCount injectedCount - * @param expectedSingleton expectedSingleton - * @param expectedType expectedType - */ - public static void verifyInjected(Provider injectee, - String tag, - Integer injectedCount, - boolean expectedSingleton, - Class expectedType) { - Objects.requireNonNull(injectee, tag + " was not injected"); - Object provided = Objects.requireNonNull(injectee.get(), tag + " was expected to be provided"); - - if (expectedType != null && !expectedType.isInstance(provided)) { - throw new AssertionError(tag + " was expected to be of type " + expectedType + " : " + provided); - } - - Object provided2 = injectee.get(); - if (expectedSingleton && provided != provided2) { - throw new AssertionError(tag + " was expected to be a singleton provided type"); - } - if (expectedType != null && !(expectedType.isInstance(provided2))) { - throw new AssertionError(tag + " was expected to be of type " + expectedType + " : " + provided2); - } - - if (injectedCount != null && injectedCount != 1) { - throw new AssertionError(tag - + " was was expected to be injected 1 time; it was actually injected " - + injectedCount + " times"); - } - } - - /** - * Testing. - * - * @param injectee injectee - * @param tag tag - * @param injectedCount injectedCount - * @param expectedSize expectedSize - * @param expectedType expectedType - */ - public static void verifyInjected(List injectee, - String tag, - Integer injectedCount, - int expectedSize, - Class expectedType) { - Objects.requireNonNull(injectee, tag + " was not injected"); - - int size = injectee.size(); - if (size != expectedSize) { - throw new AssertionError(tag + " was expected to be size of " + expectedSize - + " but instead was injected with: " + injectee); - } - - if (injectedCount != null && injectedCount != 1) { - throw new AssertionError(tag - + " was was expected to be injected 1 time; it was actually injected " - + injectedCount + " times"); - } - - if (expectedType != null) { - injectee.forEach(item -> { - if (!expectedType.isInstance(item)) { - throw new AssertionError(tag + " was expected to be of type " + expectedType + " : " + item); - } - }); - } - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/TestNamed.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/TestNamed.java deleted file mode 100644 index 9ff407bfdca..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/TestNamed.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.interceptor; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import io.helidon.inject.api.InterceptedTrigger; - -/** - * Used as an {@link InterceptedTrigger} from the maven-plugin call (see pom.xml). - */ -//@InterceptedTrigger - intentional decision not to add this in order to avoid standard annotation processing. -// it will instead be handled by the maven-plugin -@Retention(RetentionPolicy.CLASS) -public @interface TestNamed { - - /** - * For testing only. - * - * @return for testing only - */ - String value(); - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/XImpl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/XImpl.java deleted file mode 100644 index 27c50b25d53..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/XImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.interceptor; - -import java.io.Closeable; -import java.io.IOException; -import java.util.Optional; - -import io.helidon.inject.api.InterceptedTrigger; -import io.helidon.inject.api.ClassNamed; -import io.helidon.inject.api.ExternalContracts; -import io.helidon.inject.tests.inject.ClassNamedX; -import io.helidon.inject.tests.plain.interceptor.IA; -import io.helidon.inject.tests.plain.interceptor.IB; -import io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -/** - * This test case is applying {@link InterceptorBasedAnno} (an {@link InterceptedTrigger}) using the no-arg - * constructor approach - all methods are intercepted. - *

- * Also note that interception was triggered by the presence of the {@link TestNamed} and {@link InterceptorBasedAnno} triggers. - */ -@Singleton -@ClassNamed(ClassNamedX.class) -@TestNamed("TestNamed-ClassX") -@ExternalContracts(value = Closeable.class, moduleNames = {"test1", "test2"}) -@SuppressWarnings("unused") -public class XImpl implements IA, IB, Closeable { - - XImpl() { - } - - @Inject - // will be intercepted - XImpl(Optional optionalIA) { - assert (optionalIA.isEmpty()); - } - - // a decoy constructor (and will not be intercepted) - @InterceptorBasedAnno("IA2") - XImpl(IB ib) { - throw new IllegalStateException("should not be here"); - } - - @Override - // will be intercepted - public void methodIA1() { - } - - @InterceptorBasedAnno("IA2") - @Override - // will be intercepted - public void methodIA2() { - } - - @Named("methodIB") - @InterceptorBasedAnno("IBSubAnno") - @Override - // will be intercepted - public void methodIB(@Named("arg1") String val) { - } - - @Named("methodIB2") - @InterceptorBasedAnno("IBSubAnno") - @Override - // will be intercepted - public String methodIB2(@Named("arg1") String val) { - return val; - } - - @InterceptorBasedAnno - @Override - public void close() throws IOException, RuntimeException { - throw new IOException("forced"); - } - - // will be intercepted - public long methodX(String arg1, - int arg2, - boolean arg3) throws IOException, RuntimeException, AssertionError { - return 101; - } - - // test of package private - // will be intercepted - String methodY() { - return "methodY"; - } - - // test of protected - // will be intercepted - protected String methodZ() { - return "methodZ"; - } - - // test of protected - // will be intercepted - protected void throwRuntimeException() { - throw new RuntimeException("forced"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/YImpl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/YImpl.java deleted file mode 100644 index 8b37488da93..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/interceptor/YImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.interceptor; - -import java.io.Closeable; -import java.io.IOException; -import java.util.Optional; - -import io.helidon.inject.api.InterceptedTrigger; -import io.helidon.inject.api.ClassNamed; -import io.helidon.inject.api.ExternalContracts; -import io.helidon.inject.tests.inject.ClassNamedY; -import io.helidon.inject.tests.plain.interceptor.IA; -import io.helidon.inject.tests.plain.interceptor.IB; -import io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -/** - * This test case is applying {@link InterceptorBasedAnno} (an {@link InterceptedTrigger}) on only - * the {@link IB} interface. - *

- * Also note that interception was triggered by the presence of the {@link InterceptorBasedAnno} trigger. - */ -@Singleton -@ClassNamed(ClassNamedY.class) -@ExternalContracts(value = Closeable.class, moduleNames = {"test1", "test2"}) -@SuppressWarnings("unused") -public class YImpl implements IB, Closeable { - - // intentionally w/o a default constructor - do not uncomment -// YImpl() { -// } - - @Inject - // will be intercepted - YImpl(Optional optionalIA) { - assert (optionalIA.isPresent() && optionalIA.get().getClass().getName().contains("XImpl")); - } - - // a decoy constructor (and will not be intercepted) - @InterceptorBasedAnno("IA2") - YImpl(IB ib) { - throw new IllegalStateException("should not be here"); - } - - @Named("methodIB") - @InterceptorBasedAnno("IBSubAnno") - @Override - // will be intercepted - public void methodIB(@Named("arg1") String val) { - } - - @Named("methodIB2") - @InterceptorBasedAnno("IBSubAnno") - @Override - // will be intercepted - public String methodIB2(@Named("arg1") String val) { - return val; - } - - @InterceptorBasedAnno - @Override - // will be intercepted - public void close() throws IOException, RuntimeException { - throw new IOException("forced"); - } - - // will not be intercepted - public long methodX(String arg1, - int arg2, - boolean arg3) throws IOException, RuntimeException, AssertionError { - return 101; - } - - // will not be intercepted - String methodY() { - return "methodY"; - } - - // will not be intercepted - protected String methodZ() { - return "methodZ"; - } - - // will not be intercepted - protected void throwRuntimeException() { - throw new RuntimeException("forced"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/package-info.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/package-info.java deleted file mode 100644 index b2f12157da4..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Testing. - */ -package io.helidon.inject.tests.inject; diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/FakeConfig.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/FakeConfig.java deleted file mode 100644 index 1877c9aa856..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/FakeConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.provider; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.inject.tests.inject.tbox.Preferred; - -import jakarta.inject.Singleton; - -public interface FakeConfig { - - interface B { - - } - - @Singleton - @Preferred("x") - @Weight(Weighted.DEFAULT_WEIGHT) - class Builder implements B { - } - - @Singleton - @Weight(Weighted.DEFAULT_WEIGHT+1) - class HigherWeightBuilder extends Builder { - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/FakeServer.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/FakeServer.java deleted file mode 100644 index ffacc4e0191..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/FakeServer.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.provider; - -import io.helidon.inject.tests.inject.tbox.Preferred; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -public interface FakeServer { - - interface B { - - } - - @Singleton - class Builder implements B { - @Inject - Builder(@Preferred("x") FakeConfig.Builder b) { - assert (b.getClass() == FakeConfig.Builder.class) : String.valueOf(b); - } - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/MyConcreteClassContract.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/MyConcreteClassContract.java deleted file mode 100644 index 8ff82080929..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/MyConcreteClassContract.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.provider; - -public class MyConcreteClassContract { - - private final String id; - - MyConcreteClassContract(String id) { - this.id = id; - } - - @Override - public String toString() { - return id; - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/MyServices.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/MyServices.java deleted file mode 100644 index 5ad3b101c89..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/provider/MyServices.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.provider; - -import java.util.Objects; -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.InjectionPointProvider; - -import jakarta.annotation.PostConstruct; -import jakarta.inject.Inject; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -public class MyServices { - - @Singleton - public static class MyConcreteClassContractPerRequestProvider implements Provider { - private volatile int counter; - - @Override - public MyConcreteClassContract get() { - int num = counter++; - return new MyConcreteClassContract(getClass().getSimpleName() + ":instance_" + num); - } - } - - @Singleton - @Weight(Weighted.DEFAULT_WEIGHT + 1) - public static class MyConcreteClassContractPerRequestIPProvider implements InjectionPointProvider { - private volatile int counter; - - private boolean postConstructed; - private MyConcreteClassContract injected; - - @PostConstruct - public void postConstruct() { - assert (injected != null); - postConstructed = true; - } - - @Override - public Optional first(ContextualServiceQuery query) { - assert (injected != null); - assert (postConstructed); - int num = counter++; - String id = getClass().getSimpleName() + ":instance_" + num + ", " + injected; - return Optional.of(new MyConcreteClassContract(id)); - } - - @Inject - void setMyConcreteClassContract(MyConcreteClassContract injected) { - assert (this.injected == null); - this.injected = Objects.requireNonNull(injected); - } - - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/CommonContract.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/CommonContract.java deleted file mode 100644 index 970add16316..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/CommonContract.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.stacking; - -import io.helidon.inject.api.Contract; - -/** - * All implementors will implement this {@link Contract}, but using varying {@link io.helidon.common.Weight}'s. - */ -@Contract -public interface CommonContract { - - CommonContract getInner(); - - String sayHello(String arg); - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/CommonContractImpl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/CommonContractImpl.java deleted file mode 100644 index acd949ede0c..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/CommonContractImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.stacking; - -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.inject.api.RunLevel; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT + 1) -@RunLevel(1) -@Named("InterceptedImpl") -public class CommonContractImpl implements CommonContract { - - private final CommonContract inner; - - @Inject - public CommonContractImpl(Optional inner) { - this.inner = inner.orElse(null); - } - - @Override - public CommonContract getInner() { - return inner; - } - - @Override - public String sayHello(String arg) { - return getClass().getSimpleName() + ":" + (inner != null ? inner.sayHello(arg) : arg); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/MostOuterCommonContractImpl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/MostOuterCommonContractImpl.java deleted file mode 100644 index c84c8d5019b..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/MostOuterCommonContractImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.stacking; - -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT + 3) -public class MostOuterCommonContractImpl extends OuterCommonContractImpl { - - @Inject - public MostOuterCommonContractImpl(Optional inner) { - super(inner); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/OuterCommonContractImpl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/OuterCommonContractImpl.java deleted file mode 100644 index b661df9363a..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/stacking/OuterCommonContractImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.stacking; - -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT + 2) -public class OuterCommonContractImpl extends CommonContractImpl { - - @Inject - public OuterCommonContractImpl(Optional inner) { - super(inner); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/AbstractBlade.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/AbstractBlade.java deleted file mode 100644 index 845fabf4119..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/AbstractBlade.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import io.helidon.inject.api.OptionallyNamed; - -import jakarta.inject.Inject; - -public abstract class AbstractBlade implements OptionallyNamed { - - // intended to be a void injection point - @Inject - protected AbstractBlade() { - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/AbstractSaw.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/AbstractSaw.java deleted file mode 100644 index d190a0dd0a1..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/AbstractSaw.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import java.util.List; -import java.util.Optional; - -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.tests.inject.tbox.impl.DullBlade; -import io.helidon.inject.tests.inject.Verification; - -import jakarta.inject.Inject; -import jakarta.inject.Provider; - -public abstract class AbstractSaw extends Verification implements Tool { - @Inject protected Provider fieldInjectedProtectedProviderInAbstractBase; - @Inject protected Optional fieldInjectedProtectedOptionalInAbstractBase; - @Inject protected List fieldInjectedProtectedListInAbstractBase; - @Inject protected List fieldInjectedProtectedProviderListInAbstractBase; - - @Inject Provider fieldInjectedPkgPrivateProviderInAbstractBase; - @Inject Optional fieldInjectedPkgPrivateOptionalInAbstractBase; - @Inject List fieldInjectedPkgPrivateListInAbstractBase; - @Inject List> fieldInjectedPkgPrivateProviderListInAbstractBase; - - Provider setterInjectedPkgPrivateProviderInAbstractBase; - Optional setterInjectedPkgPrivateOptionalInAbstractBase; - List setterInjectedPkgPrivateListInAbstractBase; - List> setterInjectedPkgPrivateProviderListInAbstractBase; - - int setterInjectedPkgPrivateProviderInAbstractBaseInjectedCount; - int setterInjectedPkgPrivateOptionalInAbstractBaseInjectedCount; - int setterInjectedPkgPrivateListInAbstractBaseInjectedCount; - int setterInjectedPkgPrivateProviderListInAbstractBaseInjectedCount; - - @Inject - void setBladeProvider(Provider blade) { - setterInjectedPkgPrivateProviderInAbstractBase = blade; - setterInjectedPkgPrivateProviderInAbstractBaseInjectedCount++; - } - - @Inject - void setBladeOptional(Optional blade) { - setterInjectedPkgPrivateOptionalInAbstractBase = blade; - setterInjectedPkgPrivateOptionalInAbstractBaseInjectedCount++; - } - - @Inject - void setBladeList(List blades) { - setterInjectedPkgPrivateListInAbstractBase = blades; - setterInjectedPkgPrivateListInAbstractBaseInjectedCount++; - } - - @Inject - public void setBladeProviders(List> blades) { - setterInjectedPkgPrivateProviderListInAbstractBase = blades; - setterInjectedPkgPrivateProviderListInAbstractBaseInjectedCount++; - } - - public void verifyState() { - verifyInjected(fieldInjectedProtectedOptionalInAbstractBase, getClass() - + ".fieldInjectedProtectedOptionalInAbstractBase", null, true, DullBlade.class); - verifyInjected(fieldInjectedProtectedProviderInAbstractBase, getClass() - + ".fieldInjectedProtectedProviderInAbstractBase", null, true, DullBlade.class); - verifyInjected(fieldInjectedProtectedListInAbstractBase, getClass() - + ".fieldInjectedProtectedListInAbstractBase", null, 1, AbstractBlade.class); - verifyInjected(setterInjectedPkgPrivateProviderListInAbstractBase, getClass() - + ".setterInjectedPkgPrivateProviderListInAbstractBase", null, 1, ServiceProvider.class); - - verifyInjected(fieldInjectedPkgPrivateProviderInAbstractBase, getClass() - + ".fieldInjectedPkgPrivateProviderInAbstractBase", null, true, DullBlade.class); - verifyInjected(fieldInjectedPkgPrivateOptionalInAbstractBase, getClass() - + ".fieldInjectedPkgPrivateOptionalInAbstractBase", null, true, DullBlade.class); - verifyInjected(fieldInjectedPkgPrivateListInAbstractBase, getClass() - + ".fieldInjectedPkgPrivateListInAbstractBase", null, 1, DullBlade.class); - verifyInjected(fieldInjectedPkgPrivateProviderListInAbstractBase, getClass() - + ".fieldInjectedPkgPrivateProviderListInAbstractBase", null, 1, ServiceProvider.class); - - verifyInjected(setterInjectedPkgPrivateProviderInAbstractBase, getClass() - + ".setBladeProvider(Provider blade)", - setterInjectedPkgPrivateProviderInAbstractBaseInjectedCount, true, DullBlade.class); - verifyInjected(setterInjectedPkgPrivateOptionalInAbstractBase, getClass() - + ".setBladeOptional(Optional blade)", - setterInjectedPkgPrivateOptionalInAbstractBaseInjectedCount, true, DullBlade.class); - verifyInjected(setterInjectedPkgPrivateListInAbstractBase, getClass() - + ".setBladeList(List blades)", - setterInjectedPkgPrivateListInAbstractBaseInjectedCount, 1, DullBlade.class); - verifyInjected(fieldInjectedPkgPrivateProviderListInAbstractBase, getClass() - + ".fieldInjectedPkgPrivateProviderListInAbstractBase", null, 1, ServiceProvider.class); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Awl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Awl.java deleted file mode 100644 index 5703628aa13..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Awl.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import io.helidon.inject.api.Contract; - -/** - * Testing. - */ -@Contract -public interface Awl extends Tool { - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Hammer.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Hammer.java deleted file mode 100644 index 829285dd1d4..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Hammer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import io.helidon.inject.api.Contract; -import io.helidon.inject.api.OptionallyNamed; - -/** - * Testing. - */ -@Contract -public interface Hammer extends Tool, OptionallyNamed { - - @Override - default String name() { - return "hammer"; - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Lubricant.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Lubricant.java deleted file mode 100644 index b28e40826f0..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Lubricant.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -/** - * Testing. - */ -// @Singleton -- intentionally not declared to be a contract -public interface Lubricant { - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Preferred.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Preferred.java deleted file mode 100644 index 8f3b80ea0ce..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Preferred.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import jakarta.inject.Qualifier; - -/** - * Custom qualifier. - */ -@Qualifier -@Documented -@Retention(RetentionPolicy.CLASS) -public @interface Preferred { - - /** - * Testing. - * - * @return for testing - */ - String value() default ""; - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/TableSaw.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/TableSaw.java deleted file mode 100644 index 9cba413c263..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/TableSaw.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import java.util.List; -import java.util.Optional; - -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.tests.inject.tbox.impl.CoarseBlade; -import io.helidon.inject.tests.inject.tbox.impl.DullBlade; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -/** - * Intentionally in the same package as {AbstractSaw}. - */ -@Singleton -@SuppressWarnings("unused") -public class TableSaw extends AbstractSaw { - - private Optional ctorInjectedLubricantInSubClass; - private Optional setterInjectedLubricantInSubClass; - - private int setterInjectedLubricantInSubClassInjectedCount; - - @Inject @Named(CoarseBlade.NAME) Provider coarseBladeFieldInjectedPkgPrivateProviderInSubClass; - @Inject @Named(CoarseBlade.NAME) Optional coarseBladeFieldInjectedPkgPrivateOptionalInSubClass; - @Inject @Named(CoarseBlade.NAME) List coarseBladeFieldInjectedPkgPrivateListInSubClass; - @Inject @Named(CoarseBlade.NAME) List> coarseBladeFieldInjectedPkgPrivateProviderListInSubClass; - - Provider setterInjectedPkgPrivateProviderInSubClass; - Optional setterInjectedPkgPrivateOptionalInSubClass; - List setterInjectedPkgPrivateListInSubClass; - List> setterInjectedPkgPrivateProviderListInSubClass; - - int setterInjectedPkgPrivateProviderInSubClassInjectedCount; - int setterInjectedPkgPrivateOptionalInSubClassInjectedCount; - int setterInjectedPkgPrivateListInSubClassInjectedCount; - int setterInjectedPkgPrivateProviderListInSubClassInjectedCount; - - TableSaw() { - } - - @Inject - public TableSaw(Optional lubricant) { - ctorInjectedLubricantInSubClass = lubricant; - } - - @Override - public Optional named() { - return Optional.of(getClass().getSimpleName()); - } - - @Inject - protected void injectLubricant(Optional lubricant) { - setterInjectedLubricantInSubClass = lubricant; - setterInjectedLubricantInSubClassInjectedCount++; - } - - @Inject - void setBladeProviderInSubclass(Provider blade) { - setterInjectedPkgPrivateProviderInSubClass = blade; - setterInjectedPkgPrivateProviderInSubClassInjectedCount++; - } - - @Inject - void setBladeOptionalInSubclass(Optional blade) { - setterInjectedPkgPrivateOptionalInSubClass = blade; - setterInjectedPkgPrivateOptionalInSubClassInjectedCount++; - } - - @Inject - void setAllBladesInSubclass(@Named("*") List blades) { - setterInjectedPkgPrivateListInSubClass = blades; - setterInjectedPkgPrivateListInSubClassInjectedCount++; - } - - @Inject - void setBladeProviderListInSubclass(List> blades) { - setterInjectedPkgPrivateProviderListInSubClass = blades; - setterInjectedPkgPrivateProviderListInSubClassInjectedCount++; - } - - @Override - public void verifyState() { - verifyInjected(ctorInjectedLubricantInSubClass, getClass() + "." + InjectionPointInfo.CONSTRUCTOR, null, false, null); - verifyInjected(setterInjectedLubricantInSubClass, getClass() + ".injectLubricant(Optional lubricant)", setterInjectedLubricantInSubClassInjectedCount, false, null); - - verifyInjected(coarseBladeFieldInjectedPkgPrivateProviderInSubClass, getClass() - + ".coarseBladeFieldInjectedPkgPrivateProviderInSubClass", null, true, CoarseBlade.class); - verifyInjected(coarseBladeFieldInjectedPkgPrivateOptionalInSubClass, getClass() - + ".coarseBladeFieldInjectedPkgPrivateOptionalInSubClass", null, true, CoarseBlade.class); - verifyInjected(coarseBladeFieldInjectedPkgPrivateListInSubClass, getClass() - + ".coarseBladeFieldInjectedPkgPrivateListInSubClass", null, 1, CoarseBlade.class); - - verifyInjected(setterInjectedPkgPrivateProviderInSubClass, getClass() - + ".setBladeProvider(Provider blade)", setterInjectedPkgPrivateProviderInSubClassInjectedCount, true, DullBlade.class); - verifyInjected(setterInjectedPkgPrivateOptionalInSubClass, getClass() - + ".setBladeOptional(Optional blade)", setterInjectedPkgPrivateOptionalInSubClassInjectedCount, true, DullBlade.class); - verifyInjected(setterInjectedPkgPrivateListInSubClass, getClass() - + ".setAllBladesInSubclass(List blades)", setterInjectedPkgPrivateListInSubClassInjectedCount, 3, AbstractBlade.class); - - super.verifyState(); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Tool.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Tool.java deleted file mode 100644 index f4e147d273b..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/Tool.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import io.helidon.inject.api.Contract; -import io.helidon.inject.api.OptionallyNamed; - -/** - * Testing. - */ -@Contract -public interface Tool extends OptionallyNamed { - - /** - * Testing. - * - * @return for testing - */ - default String name() { - return named().orElseThrow(); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/ToolBox.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/ToolBox.java deleted file mode 100644 index 1e0c673fe18..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/ToolBox.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import java.util.List; - -import io.helidon.inject.api.Contract; - -import jakarta.inject.Provider; - -/** - * Testing. - */ -@Contract -public interface ToolBox { - - /** - * Testing. - * - * @return for testing - */ - List> toolsInBox(); - - /** - * Testing. - * - * @return for testing - */ - Provider preferredHammer(); - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/AwlImpl.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/AwlImpl.java deleted file mode 100644 index 60e6cb14a91..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/AwlImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.Optional; - -import io.helidon.inject.api.OptionallyNamed; -import io.helidon.inject.tests.inject.tbox.Awl; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -public class AwlImpl implements Awl, OptionallyNamed { - - @Inject - AwlImpl() { - } - - @Override - public Optional named() { - return Optional.of("awl"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/BigHammer.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/BigHammer.java deleted file mode 100644 index 7ab7fcd6144..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/BigHammer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.inject.tests.inject.tbox.Hammer; -import io.helidon.inject.tests.inject.tbox.Preferred; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT + 1) -@Named(BigHammer.NAME) -@Preferred -public class BigHammer implements Hammer { - - public static final String NAME = "big"; - - @Override - public Optional named() { - return Optional.of(NAME + " hammer"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/BladeProvider.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/BladeProvider.java deleted file mode 100644 index 1a119f58308..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/BladeProvider.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.tests.inject.tbox.AbstractBlade; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -/** - * Provides contextual injection for blades. - */ -@Singleton -@Named("*") -public class BladeProvider implements InjectionPointProvider { - - static final Qualifier all = Qualifier.createNamed("*"); - static final Qualifier coarse = Qualifier.createNamed("coarse"); - static final Qualifier fine = Qualifier.createNamed("fine"); - - @Override - public Optional first(ContextualServiceQuery query) { - Objects.requireNonNull(query); - ServiceInfoCriteria criteria = query.serviceInfoCriteria(); - assert (criteria.contractsImplemented().size() == 1) : criteria; - assert (criteria.contractsImplemented().contains(TypeName.create(AbstractBlade.class))) : criteria; - - AbstractBlade blade; - if (criteria.qualifiers().contains(all) || criteria.qualifiers().contains(coarse)) { - blade = new CoarseBlade(); - } else if (criteria.qualifiers().contains(fine)) { - blade = new FineBlade(); - } else { - assert (criteria.qualifiers().isEmpty()); - blade = new DullBlade(); - } - - return Optional.of(blade); - } - - @Override - public List list(ContextualServiceQuery query) { - Objects.requireNonNull(query); - assert (query.injectionPointInfo().orElseThrow().listWrapped()) : query; - ServiceInfoCriteria criteria = query.serviceInfoCriteria(); - - List result = new ArrayList<>(); - if (criteria.qualifiers().contains(all) || criteria.qualifiers().contains(coarse)) { - result.add(new CoarseBlade()); - } - - if (criteria.qualifiers().contains(all) || criteria.qualifiers().contains(fine)) { - result.add(new FineBlade()); - } - - if (criteria.qualifiers().contains(all) || criteria.qualifiers().isEmpty()) { - result.add(new DullBlade()); - } - - if (query.expected() && result.isEmpty()) { - throw new AssertionError("expected to match: " + criteria); - } - - return result; - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/CoarseBlade.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/CoarseBlade.java deleted file mode 100644 index 3af86f148b1..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/CoarseBlade.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.Optional; - -import io.helidon.inject.tests.inject.tbox.AbstractBlade; - -import jakarta.inject.Named; - -@Named(CoarseBlade.NAME) -public class CoarseBlade extends AbstractBlade { - - public static final String NAME = "coarse"; - - @Override - public Optional named() { - return Optional.of(NAME + " blade"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/DullBlade.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/DullBlade.java deleted file mode 100644 index 329c8ae2b96..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/DullBlade.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.Optional; - -import io.helidon.inject.tests.inject.tbox.AbstractBlade; - -/** - * When a particular blade name is not "asked for" explicitly then we give out a dull blade. - */ -public class DullBlade extends AbstractBlade { - - @Override - public Optional named() { - return Optional.of("dull blade"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/FineBlade.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/FineBlade.java deleted file mode 100644 index d9c9506fb2e..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/FineBlade.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.Optional; - -import io.helidon.inject.tests.inject.tbox.AbstractBlade; - -import jakarta.inject.Named; - -@Named(FineBlade.NAME) -public class FineBlade extends AbstractBlade { - - static final String NAME = "fine"; - - @Override - public Optional named() { - return Optional.of(NAME + " blade"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/HandSaw.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/HandSaw.java deleted file mode 100644 index e7823d463de..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/HandSaw.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.List; -import java.util.Optional; - -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.tests.inject.Verification; -import io.helidon.inject.tests.inject.tbox.AbstractBlade; -import io.helidon.inject.tests.inject.tbox.AbstractSaw; -import io.helidon.inject.tests.inject.tbox.Lubricant; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -/** - * Kept intentionally in a different package from {@link AbstractSaw} for testing. - */ -@Singleton -@SuppressWarnings("unused") -public class HandSaw extends AbstractSaw { - - private Optional ctorInjectedLubricantInSubClass; - private Optional setterInjectedLubricantInSubClass; - - private int setterInjectedLubricantInSubClassInjectedCount; - - @Inject @Named(FineBlade.NAME) Provider fineBladeFieldInjectedPkgPrivateProviderInSubClass; - @Inject @Named(FineBlade.NAME) Optional fineBladeFieldInjectedPkgPrivateOptionalInSubClass; - @Inject @Named(FineBlade.NAME) List fineBladeFieldInjectedPkgPrivateListInSubClass; - - Provider setterInjectedPkgPrivateProviderInSubClass; - Optional setterInjectedPkgPrivateOptionalInSubClass; - List setterInjectedPkgPrivateListInSubClass; - List> setterInjectedAllProviderListInSubClass; - - int setterInjectedPkgPrivateProviderInSubClassInjectedCount; - int setterInjectedPkgPrivateOptionalInSubClassInjectedCount; - int setterInjectedPkgPrivateListInSubClassInjectedCount; - int setterInjectedAllProviderListInSubClassInjectedCount; - - HandSaw() { - } - - @Inject - public HandSaw(Optional lubricant) { - ctorInjectedLubricantInSubClass = lubricant; - } - - @Override - public Optional named() { - return Optional.of(getClass().getSimpleName()); - } - - @Inject - protected void injectLubricant(Optional lubricant) { - setterInjectedLubricantInSubClass = lubricant; - setterInjectedLubricantInSubClassInjectedCount++; - } - - @Inject - void setBladeProvider(Provider blade) { - setterInjectedPkgPrivateProviderInSubClass = blade; - setterInjectedPkgPrivateProviderInSubClassInjectedCount++; - } - - @Inject - void setBladeOptional(Optional blade) { - setterInjectedPkgPrivateOptionalInSubClass = blade; - setterInjectedPkgPrivateOptionalInSubClassInjectedCount++; - } - - @Inject - void setBladeList(List blades) { - setterInjectedPkgPrivateListInSubClass = blades; - setterInjectedPkgPrivateListInSubClassInjectedCount++; - } - - @Inject - @SuppressWarnings("unchecked") - void setAllBlades(@Named("*") List> blades) { - setterInjectedAllProviderListInSubClass = (List) blades; - setterInjectedAllProviderListInSubClassInjectedCount++; - } - - @Override - public void verifyState() { - Verification.verifyInjected(ctorInjectedLubricantInSubClass, getClass() - + "." + InjectionPointInfo.CONSTRUCTOR, null, false, null); - Verification.verifyInjected(setterInjectedLubricantInSubClass, getClass() - + ".injectLubricant(Optional lubricant)", setterInjectedLubricantInSubClassInjectedCount, false, null); - - Verification.verifyInjected(fineBladeFieldInjectedPkgPrivateProviderInSubClass, getClass() - + ".fineBladeFieldInjectedPkgPrivateProviderInSubClass", null, true, FineBlade.class); - Verification.verifyInjected(fineBladeFieldInjectedPkgPrivateOptionalInSubClass, getClass() + - ".fineBladeFieldInjectedPkgPrivateOptionalInSubClass", null, true, FineBlade.class); - Verification.verifyInjected(fineBladeFieldInjectedPkgPrivateListInSubClass, getClass() + - ".fineBladeFieldInjectedPkgPrivateListInSubClass", null, 1, FineBlade.class); - - Verification.verifyInjected(setterInjectedPkgPrivateProviderInSubClass, getClass() + - ".setBladeProvider(Provider blade)", setterInjectedPkgPrivateProviderInSubClassInjectedCount, true, DullBlade.class); - Verification.verifyInjected(setterInjectedPkgPrivateOptionalInSubClass, getClass() + - ".setBladeOptional(Optional blade)", setterInjectedPkgPrivateOptionalInSubClassInjectedCount, true, DullBlade.class); - Verification.verifyInjected(setterInjectedPkgPrivateListInSubClass, getClass() + - ".setBladeList(List blades)", setterInjectedPkgPrivateListInSubClassInjectedCount, 1, AbstractBlade.class); - Verification.verifyInjected(setterInjectedAllProviderListInSubClass, getClass() + - ".setAllBlades(List blades)", setterInjectedAllProviderListInSubClassInjectedCount, 1, ServiceProvider.class); - List blades = setterInjectedAllProviderListInSubClass.get(0) - .list(ContextualServiceQuery.builder() - .serviceInfoCriteria(ServiceInfoCriteria.builder() - .addContractImplemented(AbstractBlade.class) - .build()) - .build()); - Verification.verifyInjected(blades, getClass() + - "", null, 3, AbstractBlade.class); - - super.verifyState(); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/LittleHammer.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/LittleHammer.java deleted file mode 100644 index 3ff2b44d8bf..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/LittleHammer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.Optional; - -import io.helidon.inject.tests.inject.tbox.Hammer; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Singleton -@Named(LittleHammer.NAME) -public class LittleHammer implements Hammer { - - public static final String NAME = "little"; - - @Override - public Optional named() { - return Optional.of(NAME + " hammer"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/MainToolBox.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/MainToolBox.java deleted file mode 100644 index 019cadd4646..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/MainToolBox.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.List; -import java.util.Objects; - -import io.helidon.inject.tests.inject.tbox.Hammer; -import io.helidon.inject.tests.inject.tbox.Preferred; -import io.helidon.inject.tests.inject.tbox.Tool; -import io.helidon.inject.tests.inject.tbox.ToolBox; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@SuppressWarnings("unused") -@Singleton -public class MainToolBox implements ToolBox { - - private final List> allTools; - private final List> allHammers; - private final Provider bigHammer; - private final Screwdriver screwdriver; - - private Provider setPreferredHammer; - - @Inject - @Preferred - Provider preferredHammer; - - public int postConstructCallCount; - public int preDestroyCallCount; - public int setterCallCount; - - @Inject - MainToolBox(List> allTools, - Screwdriver screwdriver, - @Named("big") Provider bigHammer, - List> allHammers) { - this.allTools = Objects.requireNonNull(allTools); - this.screwdriver = Objects.requireNonNull(screwdriver); - this.bigHammer = bigHammer; - this.allHammers = allHammers; - } - - @Inject - void setScrewdriver(Screwdriver screwdriver) { - assert(this.screwdriver == screwdriver); - setterCallCount++; - } - - @Inject - void setPreferredHammer(@Preferred Provider hammer) { - this.setPreferredHammer = hammer; - } - - @Override - public List> toolsInBox() { - return allTools; - } - - @Override - public Provider preferredHammer() { - return preferredHammer; - } - - public List> allHammers() { - return allHammers; - } - - public Provider bigHammer() { - return bigHammer; - } - - public Screwdriver screwdriver() { - return screwdriver; - } - - @PostConstruct - void postConstruct() { - postConstructCallCount++; - assert (preferredHammer == setPreferredHammer) : preferredHammer + " and " + setPreferredHammer; - } - - @PreDestroy - void preDestroy() { - preDestroyCallCount++; - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/Screwdriver.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/Screwdriver.java deleted file mode 100644 index e804d53637d..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/Screwdriver.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.io.Serializable; -import java.util.Optional; - -import io.helidon.inject.tests.inject.SomeOtherLocalNonContractInterface1; -import io.helidon.inject.tests.inject.tbox.Tool; - -import jakarta.inject.Singleton; - -@Singleton -public class Screwdriver implements Tool, SomeOtherLocalNonContractInterface1, Serializable { - - @Override - public Optional named() { - return Optional.of("screwdriver"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/SledgeHammer.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/SledgeHammer.java deleted file mode 100644 index 0d6ffacef41..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/SledgeHammer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox.impl; - -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.inject.tests.inject.tbox.Hammer; - -import jakarta.inject.Singleton; - -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT + 2) -//@Named(SledgeHammer.NAME) -public class SledgeHammer implements Hammer { - - public static final String NAME = "sledge"; - - @Override - public Optional named() { - return Optional.of(NAME + " hammer"); - } - -} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/package-info.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/package-info.java deleted file mode 100644 index 37d5e11a505..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/impl/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Testing. - */ -package io.helidon.inject.tests.inject.tbox.impl; diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/package-info.java b/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/package-info.java deleted file mode 100644 index b2d2ad32ac7..00000000000 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/tbox/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Testing. - */ -package io.helidon.inject.tests.inject.tbox; diff --git a/inject/tests/resources-inject/src/main/java/module-info.java b/inject/tests/resources-inject/src/main/java/module-info.java deleted file mode 100644 index 238f99431c2..00000000000 --- a/inject/tests/resources-inject/src/main/java/module-info.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Test Resources. - */ -module io.helidon.inject.tests.inject { - requires static jakarta.inject; - requires static jakarta.annotation; - - requires io.helidon.common.types; - requires io.helidon.common; - requires io.helidon.inject.api; - requires io.helidon.inject.runtime; - requires io.helidon.inject.tests.plain; - requires io.helidon.config; - - exports io.helidon.inject.tests.inject; - exports io.helidon.inject.tests.inject.interceptor; - exports io.helidon.inject.tests.inject.stacking; - exports io.helidon.inject.tests.inject.tbox; - - provides io.helidon.inject.api.ModuleComponent with io.helidon.inject.tests.inject.Injection$$Module; - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/AnApplicationScopedService.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/AnApplicationScopedService.java deleted file mode 100644 index cac80cc3abd..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/AnApplicationScopedService.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Default; - -/** - * {@link jakarta.enterprise.context.ApplicationScoped} is normally unsupported, and as such needs a -A entry in pom.xml - * to get it to map to {@link jakarta.inject.Singleton scope.} - */ -@ApplicationScoped -@Default -public class AnApplicationScopedService { - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/EmptyListInjectionTest.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/EmptyListInjectionTest.java deleted file mode 100644 index 9d81821dd87..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/EmptyListInjectionTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import io.helidon.config.Config; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.testing.InjectionTestingSupport.basicTestableConfig; -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -class EmptyListInjectionTest { - private static final Config CONFIG = basicTestableConfig(); - - private Services services; - - @BeforeEach - void setUp() { - this.services = testableServices(CONFIG).services(); - } - - @AfterEach - void tearDown() { - resetAll(); - } - - @Test - void acceptEmptyListInjectables() { - ServiceProvider sp = - services.lookupFirst(AServiceUsingAContractWithNoServiceImplementations.class); - assertThat(sp.get(), notNullValue()); - } - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/JavaxTest.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/JavaxTest.java deleted file mode 100644 index 7029ac8940c..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/JavaxTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import io.helidon.config.Config; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.tools.Options; -import io.helidon.inject.tools.TypeNames; - -import jakarta.enterprise.inject.Default; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.testing.InjectionTestingSupport.basicTestableConfig; -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; - -/** - * Javax to Jakarta related tests. - */ -class JavaxTest { - private static final Config CONFIG = basicTestableConfig(); - - private Services services; - - @BeforeEach - void setUp() { - this.services = testableServices(CONFIG).services(); - } - - @AfterEach - void tearDown() { - resetAll(); - } - - /** - * Uses {@link Options#TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE}. - * This also verifies that the qualifiers were mapped over properly from javax as well. - */ - @Test - void applicationScopeToSingletonScopeTranslation() { - ServiceProvider sp = services.lookupFirst(AnApplicationScopedService.class); - assertThat(sp.toString(), - equalTo("AnApplicationScopedService:INIT")); - assertThat(sp.serviceInfo().qualifiers(), - contains(Qualifier.create(Default.class))); - assertThat(sp.serviceInfo().scopeTypeNames(), - containsInAnyOrder(TypeNames.JAKARTA_SINGLETON_TYPE, TypeNames.JAKARTA_APPLICATION_SCOPED_TYPE)); - } - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/TestUtils.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/TestUtils.java deleted file mode 100644 index c1fc0a347fb..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/TestUtils.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; - -import io.helidon.inject.tools.ToolsException; - -/** - * Testing utilities. - */ -public final class TestUtils { - - private TestUtils() { - } - - /** - * Load string from resource. - * - * @param resourceNamePath the resource path - * @return the loaded string - */ - // same as from CommonUtils. - public static String loadStringFromResource(String resourceNamePath) { - try { - try (InputStream in = TestUtils.class.getClassLoader().getResourceAsStream(resourceNamePath)) { - return new String(in.readAllBytes(), StandardCharsets.UTF_8).trim(); - } - } catch (Exception e) { - throw new ToolsException("Failed to load: " + resourceNamePath, e); - } - } - - /** - * Loads a String from a file, wrapping any exception encountered to a {@link ToolsException}. - * - * @param fileName the file name to load - * @return the contents of the file - * @throws ToolsException if there were any exceptions encountered - */ - // same as from CommonUtils. - public static String loadStringFromFile(String fileName) { - try { - Path filePath = Path.of(fileName); - String content = Files.readString(filePath); - return content.trim(); - } catch (IOException e) { - throw new ToolsException("Unable to load from file: " + fileName, e); - } - } - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/TestingSingleton.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/TestingSingleton.java deleted file mode 100644 index 00df1186380..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/TestingSingleton.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject; - -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.inject.api.Resettable; -import io.helidon.inject.api.RunLevel; -import io.helidon.inject.tests.inject.stacking.CommonContract; -import io.helidon.inject.tests.inject.tbox.Awl; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@RunLevel(RunLevel.STARTUP) -@Singleton -@Named("testing") -public class TestingSingleton implements Resettable, CommonContract { - final static AtomicInteger postConstructCount = new AtomicInteger(); - final static AtomicInteger preDestroyCount = new AtomicInteger(); - - CommonContract inner; - @Inject Provider awlProvider; - - @Inject - TestingSingleton(Optional inner) { - this.inner = inner.orElseThrow(); - } - - @PostConstruct - public void voidMethodWithNoArgs() { - postConstructCount.incrementAndGet(); - } - - @PreDestroy - public void preDestroy() { - preDestroyCount.incrementAndGet(); - } - - public static int postConstructCount() { - return postConstructCount.get(); - } - - public static int preDestroyCount() { - return preDestroyCount.get(); - } - - @Override - public boolean reset(boolean deep) { - postConstructCount.set(0); - preDestroyCount.set(0); - return true; - } - - @Override - public CommonContract getInner() { - return inner; - } - - @Override - public String sayHello(String arg) { - return "TS: " + getInner().sayHello(arg); - } -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/interceptor/InterceptorRuntimeTest.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/interceptor/InterceptorRuntimeTest.java deleted file mode 100644 index 740113e467c..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/interceptor/InterceptorRuntimeTest.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.interceptor; - -import java.io.Closeable; -import java.io.File; -import java.nio.file.Files; -import java.util.Calendar; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.helidon.common.types.TypeName; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.api.InjectionException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.testing.ReflectionBasedSingletonServiceProvider; -import io.helidon.inject.tests.inject.ClassNamedY; -import io.helidon.inject.tests.plain.interceptor.IB; -import io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno; -import io.helidon.inject.tests.plain.interceptor.TestNamedInterceptor; - -import jakarta.inject.Named; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.api.Qualifier.create; -import static io.helidon.inject.api.Qualifier.createNamed; -import static io.helidon.inject.testing.InjectionTestingSupport.basicTestableConfig; -import static io.helidon.inject.testing.InjectionTestingSupport.bind; -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static io.helidon.inject.testing.InjectionTestingSupport.toDescription; -import static io.helidon.inject.testing.InjectionTestingSupport.toDescriptions; -import static io.helidon.inject.tests.inject.TestUtils.loadStringFromResource; -import static io.helidon.inject.tools.TypeTools.toFilePath; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class InterceptorRuntimeTest { - - Config config = basicTestableConfig(); - InjectionServices injectionServices; - Services services; - - @BeforeEach - void setUp() { - setUp(config); - } - - void setUp(Config config) { - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); - } - - @AfterEach - void tearDown() { - resetAll(); - } - - @Test - void createNoArgBasedInterceptorSource() throws Exception { - TypeName interceptorTypeName = TypeName.create(XImpl$$Injection$$Interceptor.class); - String path = toFilePath(interceptorTypeName); - File file = new File("./target/generated-sources/annotations", path); - assertThat(file.exists(), is(true)); - String java = Files.readString(file.toPath()); - String expected = loadStringFromResource("expected/ximpl-interceptor._java_"); - assertThat( - java, - is(expected.replaceFirst("#DATE#", Integer.toString(Calendar.getInstance().get(Calendar.YEAR)))) - ); - } - - @Test - void createInterfaceBasedInterceptorSource() throws Exception { - TypeName interceptorTypeName = TypeName.create(YImpl$$Injection$$Interceptor.class); - String path = toFilePath(interceptorTypeName); - File file = new File("./target/generated-sources/annotations", path); - assertThat(file.exists(), is(true)); - String java = Files.readString(file.toPath()); - String expected = loadStringFromResource("expected/yimpl-interceptor._java_"); - assertThat( - java, - is(expected.replaceFirst("#DATE#", Integer.toString(Calendar.getInstance().get(Calendar.YEAR)))) - ); - } - - @Test - void runtimeWithNoInterception() throws Exception { - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addContractImplemented(Closeable.class) - .includeIntercepted(true) - .build(); - List> closeableProviders = services.lookupAll(criteria); - assertThat("the interceptors should always be weighted higher than the non-interceptors", - toDescriptions(closeableProviders), - contains("XImpl$$Injection$$Interceptor:INIT", "YImpl$$Injection$$Interceptor:INIT", - "XImpl:INIT", "YImpl:INIT")); - - criteria = ServiceInfoCriteria.builder() - .addContractImplemented(Closeable.class) - .includeIntercepted(false) - .build(); - closeableProviders = services.lookupAll(criteria); - assertThat("the interceptors should always be weighted higher than the non-interceptors", - toDescriptions(closeableProviders), - contains("XImpl$$Injection$$Interceptor:INIT", "YImpl$$Injection$$Interceptor:INIT")); - - List> ibProviders = services.lookupAll(IB.class); - assertThat(closeableProviders, - equalTo(ibProviders)); - - ServiceProvider ximplProvider = services.lookupFirst(XImpl.class); - assertThat(closeableProviders.get(0), - is(ximplProvider)); - - XImpl x = ximplProvider.get(); - x.methodIA1(); - x.methodIA2(); - x.methodIB("test"); - String sval = x.methodIB2("test"); - assertThat(sval, - equalTo("test")); - long val = x.methodX("a", 2, true); - assertThat(val, - equalTo(101L)); - assertThat(x.methodY(), - equalTo("methodY")); - assertThat(x.methodZ(), - equalTo("methodZ")); - InjectionException pe = assertThrows(InjectionException.class, x::close); - assertThat("the error handling should be the same if there are interceptors or not", - pe.getMessage(), - equalTo("Error in interceptor chain processing: service provider: XImpl:ACTIVE")); - RuntimeException re = assertThrows(RuntimeException.class, x::throwRuntimeException); - assertThat("the error handling should be the same if there are interceptors or not", - re.getMessage(), - equalTo("Error in interceptor chain processing: service provider: XImpl:ACTIVE")); - - // we cannot look up by service type here - we need to instead lookup by one of the interfaces - ServiceProvider yimplProvider = services - .lookupFirst( - ServiceInfoCriteria.builder() - .addContractImplemented(Closeable.class) - .qualifiers(Set.of(create(Named.class, ClassNamedY.class.getName()))) - .build()); - assertThat(toDescription(yimplProvider), - equalTo("YImpl$$Injection$$Interceptor:INIT")); - IB ibOnYInterceptor = (IB) yimplProvider.get(); - sval = ibOnYInterceptor.methodIB2("test"); - assertThat(sval, - equalTo("test")); - } - - @Test - void runtimeWithInterception() throws Exception { - // disable application and modules to effectively start with an empty registry - Config config = Config.builder( - ConfigSources.create( - Map.of("inject.permits-dynamic", "true", - "inject.uses-compile-time-applications", "false", - "inject.uses-compile-time-modules", "true"), - "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - tearDown(); - setUp(config); - bind(injectionServices, ReflectionBasedSingletonServiceProvider - .create(TestNamedInterceptor.class, - ServiceInfo.builder() - .serviceTypeName(TestNamedInterceptor.class) - .addQualifier(createNamed(TestNamed.class.getName())) - .addQualifier(createNamed(InterceptorBasedAnno.class.getName())) - .addExternalContractImplemented(Interceptor.class) - .build())); - assertThat(TestNamedInterceptor.ctorCount.get(), - equalTo(0)); - - List> closeableProviders = injectionServices.services().lookupAll(Closeable.class); - assertThat("the interceptors should always be weighted higher than the non-interceptors", - toDescriptions(closeableProviders), - contains("XImpl$$Injection$$Interceptor:INIT", "YImpl$$Injection$$Interceptor:INIT")); - - List> ibProviders = services.lookupAll(IB.class); - assertThat(closeableProviders, - equalTo(ibProviders)); - - ServiceProvider ximplProvider = services.lookupFirst(XImpl.class); - assertThat(closeableProviders.get(0), - is(ximplProvider)); - - assertThat(TestNamedInterceptor.ctorCount.get(), - equalTo(0)); - XImpl xIntercepted = ximplProvider.get(); - assertThat(TestNamedInterceptor.ctorCount.get(), - equalTo(1)); - - xIntercepted.methodIA1(); - xIntercepted.methodIA2(); - xIntercepted.methodIB("test"); - String sval = xIntercepted.methodIB2("test"); - assertThat(sval, - equalTo("intercepted:test")); - long val = xIntercepted.methodX("a", 2, true); - assertThat(val, - equalTo(202L)); - assertThat(xIntercepted.methodY(), - equalTo("intercepted:methodY")); - assertThat(xIntercepted.methodZ(), - equalTo("intercepted:methodZ")); - InjectionException pe = assertThrows(InjectionException.class, xIntercepted::close); - assertThat(pe.getMessage(), - equalTo("forced: service provider: XImpl:ACTIVE")); - RuntimeException re = assertThrows(RuntimeException.class, xIntercepted::throwRuntimeException); - assertThat(re.getMessage(), - equalTo("forced: service provider: XImpl:ACTIVE")); - - assertThat(TestNamedInterceptor.ctorCount.get(), - equalTo(1)); - - // we cannot look up by service type here - we need to instead lookup by one of the interfaces - ServiceProvider yimplProvider = services - .lookupFirst( - ServiceInfoCriteria.builder() - .addContractImplemented(Closeable.class) - .qualifiers(Set.of(create(Named.class, ClassNamedY.class.getName()))) - .build()); - assertThat(toDescription(yimplProvider), - equalTo("YImpl$$Injection$$Interceptor:INIT")); - IB ibOnYInterceptor = (IB) yimplProvider.get(); - sval = ibOnYInterceptor.methodIB2("test"); - assertThat(sval, - equalTo("intercepted:test")); - } - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/provider/PerRequestProviderTest.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/provider/PerRequestProviderTest.java deleted file mode 100644 index 5b9f8964a4a..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/provider/PerRequestProviderTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.provider; - -import io.helidon.config.Config; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.testing.InjectionTestingSupport; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; - -class PerRequestProviderTest { - - Config config = InjectionTestingSupport.basicTestableConfig(); - InjectionServices injectionServices; - Services services; - - @BeforeEach - void setUp() { - setUp(config); - } - - void setUp(Config config) { - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); - } - - @AfterEach - void tearDown() { - resetAll(); - } - - @Test - void myConcreteClassContractTest() { - ServiceProvider sp = services.lookupFirst(MyConcreteClassContract.class); - assertThat(sp.description(), - equalTo("MyServices$MyConcreteClassContractPerRequestIPProvider:INIT")); - MyConcreteClassContract instance0 = sp.get(); - assertThat(instance0.toString(), - equalTo("MyConcreteClassContractPerRequestIPProvider:instance_0, " - + "MyConcreteClassContractPerRequestProvider:instance_0")); - MyConcreteClassContract instance1 = sp.get(); - assertThat(instance1.toString(), - equalTo("MyConcreteClassContractPerRequestIPProvider:instance_1, " - + "MyConcreteClassContractPerRequestProvider:instance_0")); - } - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/stacking/InjectionOfCommonContractStackingTest.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/stacking/InjectionOfCommonContractStackingTest.java deleted file mode 100644 index 70e26d70c0a..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/stacking/InjectionOfCommonContractStackingTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.stacking; - -import java.util.List; - -import io.helidon.config.Config; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.testing.InjectionTestingSupport; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; - -/** - * Tests cases where service MostOuter injects Outer injects Inner using the same contract. - */ -class InjectionOfCommonContractStackingTest { - - Config config = InjectionTestingSupport.basicTestableConfig(); - InjectionServices injectionServices; - Services services; - - @BeforeEach - void setUp() { - setUp(config); - } - - void setUp(Config config) { - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); - } - - @AfterEach - void tearDown() { - resetAll(); - } - - @Test - void injectionStacking() { - List> allIntercepted = services.lookupAll(CommonContract.class); - List desc = allIntercepted.stream().map(ServiceProvider::description).toList(); - // order matters here - assertThat(desc, contains( - "MostOuterCommonContractImpl:INIT", - "OuterCommonContractImpl:INIT", - "CommonContractImpl:INIT", - "TestingSingleton:INIT")); - - List injections = allIntercepted.stream() - .map(sp -> { - CommonContract inner = sp.get().getInner(); - return sp.serviceInfo().serviceTypeName().classNameWithEnclosingNames() + " injected with " - + (inner == null ? null : inner.getClass().getSimpleName()); - }) - .toList(); - assertThat(injections, - contains("MostOuterCommonContractImpl injected with OuterCommonContractImpl", - "OuterCommonContractImpl injected with CommonContractImpl", - "CommonContractImpl injected with null", - "TestingSingleton injected with MostOuterCommonContractImpl")); - - assertThat(services.lookup(CommonContract.class).get().sayHello("arg"), - equalTo("MostOuterCommonContractImpl:OuterCommonContractImpl:CommonContractImpl:arg")); - } - -} diff --git a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/tbox/ToolBoxTest.java b/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/tbox/ToolBoxTest.java deleted file mode 100644 index 81e4448d86b..00000000000 --- a/inject/tests/resources-inject/src/test/java/io/helidon/inject/tests/inject/tbox/ToolBoxTest.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.inject.tbox; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.config.Config; -import io.helidon.inject.api.ActivationResult; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.RunLevel; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.testing.InjectionTestingSupport; -import io.helidon.inject.tests.inject.ASerialProviderImpl; -import io.helidon.inject.tests.inject.ClassNamedY; -import io.helidon.inject.tests.inject.TestingSingleton; -import io.helidon.inject.tests.inject.provider.FakeConfig; -import io.helidon.inject.tests.inject.provider.FakeServer; -import io.helidon.inject.tests.inject.stacking.CommonContract; -import io.helidon.inject.tests.inject.tbox.impl.BigHammer; -import io.helidon.inject.tests.inject.tbox.impl.HandSaw; -import io.helidon.inject.tests.inject.tbox.impl.MainToolBox; -import io.helidon.inject.tools.Options; - -import jakarta.inject.Provider; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.types.TypeName.create; -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static io.helidon.inject.tests.inject.TestUtils.loadStringFromFile; -import static io.helidon.inject.tests.inject.TestUtils.loadStringFromResource; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.hasEntry; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -/** - * Expectation here is that the annotation processor ran, and we can use standard injection and di registry services, etc. - */ -class ToolBoxTest { - Config config = InjectionTestingSupport.basicTestableConfig(); - InjectionServices injectionServices; - Services services; - - @BeforeEach - void setUp() { - setUp(config); - } - - void setUp(Config config) { - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); - } - - @AfterEach - void tearDown() { - resetAll(); - } - - @Test - void sanity() { - assertNotNull(injectionServices); - assertNotNull(services); - } - - @Test - void toolbox() { - List> blanks = services.lookupAll(Awl.class); - List desc = blanks.stream().map(ServiceProvider::description).collect(Collectors.toList()); - // note that order matters here - assertThat(desc, - contains("AwlImpl:INIT")); - - List> allToolBoxes = services.lookupAll(ToolBox.class); - desc = allToolBoxes.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat(desc, - contains("MainToolBox:INIT")); - - ToolBox toolBox = allToolBoxes.get(0).get(); - assertThat(toolBox.getClass(), equalTo(MainToolBox.class)); - MainToolBox mtb = (MainToolBox) toolBox; - assertThat(mtb.postConstructCallCount, equalTo(1)); - assertThat(mtb.preDestroyCallCount, equalTo(0)); - assertThat(mtb.setterCallCount, equalTo(1)); - List> allTools = mtb.toolsInBox(); - desc = allTools.stream().map(Object::toString).collect(Collectors.toList()); - assertThat(desc, - contains("SledgeHammer:INIT", - "BigHammer:INIT", - "TableSaw:INIT", - "AwlImpl:INIT", - "HandSaw:INIT", - "LittleHammer:INIT", - "Screwdriver:ACTIVE")); - assertThat(mtb.screwdriver(), notNullValue()); - - Provider hammer = Objects.requireNonNull(toolBox.preferredHammer()); - assertThat(hammer.get(), notNullValue()); - assertThat(hammer.get(), is(hammer.get())); - assertThat(BigHammer.class, equalTo(hammer.get().getClass())); - desc = allTools.stream().map(Object::toString).collect(Collectors.toList()); - assertThat(desc, - contains("SledgeHammer:INIT", - "BigHammer:ACTIVE", - "TableSaw:INIT", - "AwlImpl:INIT", - "HandSaw:INIT", - "LittleHammer:INIT", - "Screwdriver:ACTIVE")); - - desc = (((MainToolBox) toolBox).allHammers()).stream().map(Object::toString).collect(Collectors.toList()); - assertThat(desc, - contains("SledgeHammer:INIT", - "BigHammer:ACTIVE", - "LittleHammer:INIT")); - assertThat(((ServiceProvider) ((MainToolBox) toolBox).bigHammer()).description(), - equalTo("BigHammer:ACTIVE")); - } - - @Test - void testClasses() { - assertThat(services.lookupFirst(TestingSingleton.class), - notNullValue()); - } - - /** - * This assumes {@link Options#TAG_AUTO_ADD_NON_CONTRACT_INTERFACES} has - * been enabled - see pom.xml - */ - @Test - void autoExternalContracts() { - List> allSerializable = services.lookupAll(Serializable.class); - List desc = allSerializable.stream().map(ServiceProvider::description).collect(Collectors.toList()); - // note that order matters here - assertThat(desc, - contains("ASerialProviderImpl:INIT", "Screwdriver:INIT")); - } - - @Test - void providerTest() { - Serializable s1 = services.lookupFirst(Serializable.class).get(); - assertThat(s1, notNullValue()); - assertThat(ASerialProviderImpl.class + " is a higher weight and should have been returned for " + String.class, - String.class, equalTo(s1.getClass())); - assertThat(services.lookupFirst(Serializable.class).get(), not(s1)); - } - - @Test - void modules() { - List> allModules = services.lookupAll(ModuleComponent.class); - List desc = allModules.stream().map(ServiceProvider::description).collect(Collectors.toList()); - // note that order matters here - assertThat("ensure that Annotation Processors are enabled in the tools module meta-inf/services", - desc, contains("Injection$$Module:ACTIVE", "Injection$$TestModule:ACTIVE")); - List names = allModules.stream() - .sorted() - .map(m -> m.get().named().orElse(m.get().getClass().getSimpleName() + ":null")).collect(Collectors.toList()); - assertThat(names, - contains("io.helidon.inject.tests.inject", "io.helidon.inject.tests.inject/test")); - } - - /** - * The module-info that was created (by APT processing). - */ - @Test - void moduleInfo() { - assertThat(loadStringFromFile("target/inject/classes/module-info.java.inject"), - equalTo(loadStringFromResource("expected/module-info.java._inject_"))); - } - - /** - * The test version of module-info that was created (by APT processing). - */ - @Test - void testModuleInfo() { - assertThat(loadStringFromFile("target/inject/test-classes/module-info.java.inject"), - equalTo(loadStringFromResource("expected/tests-module-info.java._inject_"))); - } - - @Test - void innerClassesCanBeGenerated() { - FakeServer.Builder s1 = services.lookupFirst(FakeServer.Builder.class).get(); - assertThat(s1, notNullValue()); - assertThat(services.lookupFirst(FakeServer.Builder.class).get(), is(s1)); - - FakeConfig.Builder c1 = services.lookupFirst(FakeConfig.Builder.class).get(); - assertThat(c1, notNullValue()); - assertThat(services.lookupFirst(FakeConfig.Builder.class).get(), is(c1)); - } - - /** - * Targets {@link AbstractSaw} with derived classes of - * {@link HandSaw} and {@link TableSaw} found in different packages. - */ - @Test - void hierarchyOfInjections() { - List> saws = services.lookupAll(AbstractSaw.class); - List desc = saws.stream().map(ServiceProvider::description).collect(Collectors.toList()); - // note that order matters here - assertThat(desc, - contains("TableSaw:INIT", "HandSaw:INIT")); - for (ServiceProvider saw : saws) { - saw.get().verifyState(); - } - } - - /** - * This tests the presence of module(s) + application(s) to handle all bindings, with effectively no lookups. - */ - @Test - void runlevel() { - assertThat("we start with 2 because we are looking for interceptors (which there is 2 here in this module)", - injectionServices.metrics().orElseThrow().lookupCount().orElseThrow(), - equalTo(2)); - List> runLevelServices = services - .lookupAll(ServiceInfoCriteria.builder().runLevel(RunLevel.STARTUP).build(), true); - List desc = runLevelServices.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat(desc, - contains("TestingSingleton:INIT")); - - runLevelServices.forEach(sp -> Objects.requireNonNull(sp.get(), sp + " failed on get()")); - assertThat("activation should not triggered one new lookup from startup", - injectionServices.metrics().orElseThrow().lookupCount().orElseThrow(), - equalTo(3)); - desc = runLevelServices.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat(desc, - contains("TestingSingleton:ACTIVE")); - } - - /** - * This assumes the presence of module(s) + application(s) to handle all bindings, with effectively no lookups! - */ - @Test - void noServiceActivationRequiresLookupWhenApplicationIsPresent() { - List> allServices = services - .lookupAll(ServiceInfoCriteria.builder().build(), true); - allServices.stream() - .filter(sp -> !(sp instanceof Provider)) - .forEach(sp -> { - sp.get(); - assertThat("activation should not have triggered any lookups (for singletons): " - + sp + " triggered lookups", injectionServices.metrics().orElseThrow().lookupCount(), - equalTo(1)); - }); - } - - @Test - void startupAndShutdownCallsPostConstructAndPreDestroy() { - assertThat(TestingSingleton.postConstructCount(), equalTo(0)); - assertThat(TestingSingleton.preDestroyCount(), equalTo(0)); - - List> allInterceptedBefore = services.lookupAll(CommonContract.class); - assertThat(allInterceptedBefore.size(), greaterThan(0)); - assertThat(TestingSingleton.postConstructCount(), equalTo(0)); - assertThat(TestingSingleton.preDestroyCount(), equalTo(0)); - allInterceptedBefore.forEach(ServiceProvider::get); - - TestingSingleton testingSingletonFromLookup = services.lookup(TestingSingleton.class).get(); - assertThat(testingSingletonFromLookup, notNullValue()); - assertThat(TestingSingleton.postConstructCount(), equalTo(1)); - assertThat(TestingSingleton.preDestroyCount(), equalTo(0)); - - Map map = injectionServices.shutdown().orElseThrow(); - Map report = map.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - e -> e.getValue().startingActivationPhase().toString() - + "->" + e.getValue().finishingActivationPhase())); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.Injection$$Application"), "ACTIVE->DESTROYED")); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.Injection$$Module"), "ACTIVE->DESTROYED")); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.Injection$$TestApplication"), "ACTIVE->DESTROYED")); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.Injection$$TestModule"), "ACTIVE->DESTROYED")); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.stacking.MostOuterCommonContractImpl"), "ACTIVE->DESTROYED")); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.stacking.OuterCommonContractImpl"), "ACTIVE->DESTROYED")); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.stacking.CommonContractImpl"), "ACTIVE->DESTROYED")); - assertThat(report, hasEntry(create("io.helidon.inject.tests.inject.TestingSingleton"), "ACTIVE->DESTROYED")); - assertThat(report + " : expected 8 services to be present", report.size(), equalTo(8)); - - assertThat(TestingSingleton.postConstructCount(), equalTo(1)); - assertThat(TestingSingleton.preDestroyCount(), equalTo(1)); - - assertThat(injectionServices.metrics().orElseThrow().lookupCount().orElse(0), equalTo(0)); - - tearDown(); - setUp(); - TestingSingleton testingSingletonFromLookup2 = injectionServices.services().lookup(TestingSingleton.class).get(); - assertThat(testingSingletonFromLookup2, not(testingSingletonFromLookup)); - - map = injectionServices.shutdown().orElseThrow(); - report = map.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - e2 -> e2.getValue().startingActivationPhase().toString() - + "->" + e2.getValue().finishingActivationPhase())); - assertThat(report.toString(), report.size(), is(8)); - - tearDown(); - map = injectionServices.shutdown().orElseThrow(); - assertThat(map.toString(), map.size(), is(0)); - } - - @Test - void knownProviders() { - List> providers = services.lookupAll( - ServiceInfoCriteria.builder().addContractImplemented(Provider.class).build()); - List desc = providers.stream().map(ServiceProvider::description).collect(Collectors.toList()); - // note that order matters here (weight ranked) - assertThat(desc, - contains("ASerialProviderImpl:INIT", - "MyServices$MyConcreteClassContractPerRequestIPProvider:INIT", - "MyServices$MyConcreteClassContractPerRequestProvider:INIT", - "BladeProvider:INIT")); - } - - @Test - void classNamed() { - List> providers = services.lookupAll( - ServiceInfoCriteria.builder() - .addQualifier(Qualifier.createNamed(ClassNamedY.class)) - .build()); - List desc = providers.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat(desc, - contains("YImpl$$Injection$$Interceptor:INIT", - "BladeProvider:INIT")); - - providers = services.lookupAll( - ServiceInfoCriteria.builder() - .addQualifier(Qualifier.createNamed(ClassNamedY.class.getName())) - .build()); - List desc2 = providers.stream().map(ServiceProvider::description).collect(Collectors.toList()); - assertThat(desc2, - equalTo(desc)); - } - -} diff --git a/inject/tests/resources-inject/src/test/resources/expected/module-info.java._inject_ b/inject/tests/resources-inject/src/test/resources/expected/module-info.java._inject_ deleted file mode 100644 index abb40c2b451..00000000000 --- a/inject/tests/resources-inject/src/test/resources/expected/module-info.java._inject_ +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Test Resources. - */ -module io.helidon.inject.tests.inject { - requires static jakarta.inject; - requires static jakarta.annotation; - - requires io.helidon.common.types; - requires io.helidon.common; - requires io.helidon.inject.api; - requires io.helidon.inject.runtime; - requires io.helidon.inject.tests.plain; - requires io.helidon.config; - - exports io.helidon.inject.tests.inject; - exports io.helidon.inject.tests.inject.interceptor; - exports io.helidon.inject.tests.inject.stacking; - exports io.helidon.inject.tests.inject.tbox; - - provides io.helidon.inject.api.ModuleComponent with io.helidon.inject.tests.inject.Injection$$Module; - // External contract usage - @io.helidon.common.Generated(value = "io.helidon.inject.tools.ActivatorCreatorDefault", trigger = "io.helidon.inject.tools.ActivatorCreatorDefault") - requires test1; - requires test2; - // Contract usage - @io.helidon.common.Generated(value = "io.helidon.inject.tools.ActivatorCreatorDefault", trigger = "io.helidon.inject.tools.ActivatorCreatorDefault") - exports io.helidon.inject.tests.inject.provider; - // Application - @io.helidon.common.Generated(value = "io.helidon.inject.tools.ApplicationCreatorDefault", trigger = "io.helidon.inject.tools.ApplicationCreatorDefault") - provides io.helidon.inject.api.Application with io.helidon.inject.tests.inject.Injection$$Application; -} diff --git a/inject/tests/resources-inject/src/test/resources/expected/tests-module-info.java._inject_ b/inject/tests/resources-inject/src/test/resources/expected/tests-module-info.java._inject_ deleted file mode 100644 index 344f5a2b6c3..00000000000 --- a/inject/tests/resources-inject/src/test/resources/expected/tests-module-info.java._inject_ +++ /dev/null @@ -1,10 +0,0 @@ -// @io.helidon.common.Generated(value = "io.helidon.inject.tools.ActivatorCreatorDefault", trigger = "io.helidon.inject.tools.ActivatorCreatorDefault") -module io.helidon.inject.tests.inject/test { - exports io.helidon.inject.tests.inject; - // Module Component - @io.helidon.common.Generated(value = "io.helidon.inject.tools.ActivatorCreatorDefault", trigger = "io.helidon.inject.tools.ActivatorCreatorDefault") - provides io.helidon.inject.api.ModuleComponent with io.helidon.inject.tests.inject.Injection$$TestModule; - // Injection Runtime - @io.helidon.common.Generated(value = "io.helidon.inject.tools.ActivatorCreatorDefault", trigger = "io.helidon.inject.tools.ActivatorCreatorDefault") - requires transitive io.helidon.inject.runtime; - // Application - @io.helidon.common.Generated(value = "io.helidon.inject.tools.ApplicationCreatorDefault", trigger = "io.helidon.inject.tools.ApplicationCreatorDefault") - provides io.helidon.inject.api.Application with io.helidon.inject.tests.inject.Injection$$TestApplication; -} diff --git a/inject/tests/resources-inject/src/test/resources/expected/ximpl-interceptor._java_ b/inject/tests/resources-inject/src/test/resources/expected/ximpl-interceptor._java_ deleted file mode 100644 index 45ed09ad116..00000000000 --- a/inject/tests/resources-inject/src/test/resources/expected/ximpl-interceptor._java_ +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright (c) #DATE# Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package io.helidon.inject.tests.inject.interceptor; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.common.types.TypeValues; -import io.helidon.inject.api.ClassNamed; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.runtime.InterceptedMethod; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -import static io.helidon.common.types.TypeName.create; -import static io.helidon.inject.runtime.Invocation.createInvokeAndSupply; -import static io.helidon.inject.runtime.Invocation.mergeAndCollapse; - -/** - * Injection {@link Interceptor} for {@link io.helidon.inject.tests.inject.interceptor.XImpl }. - */ -// using the no-arg constructor approach -@io.helidon.common.Weight(100.001) -@io.helidon.inject.api.Intercepted(io.helidon.inject.tests.inject.interceptor.XImpl.class) -@Singleton -@SuppressWarnings("ALL") -@io.helidon.common.Generated(value = "io.helidon.inject.tools.InterceptorCreatorDefault", trigger = "io.helidon.inject.tests.inject.interceptor.XImpl") -public class XImpl$$Injection$$Interceptor extends io.helidon.inject.tests.inject.interceptor.XImpl { - private static final List __serviceLevelAnnotations = List.of( - Annotation.create(jakarta.inject.Singleton.class), - Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX")), - Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX")), - Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable"))), - Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))); - - private static final TypedElementInfo __ctor = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_CONSTRUCTOR) - .elementName(io.helidon.inject.api.ElementInfo.CONSTRUCTOR) - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(jakarta.inject.Inject.class)) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIA1 = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodIA1") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIA2 = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodIA2") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class, Map.of("value", "IA2"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIB = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodIB") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class, Map.of("value", "IBSubAnno"))) - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "methodIB"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIB__p1 = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("p1") - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "arg1"))) - .build(); - private static final TypedElementInfo __methodIB2 = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodIB2") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class, Map.of("value", "IBSubAnno"))) - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "methodIB2"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIB2__p1 = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("p1") - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "arg1"))) - .build(); - private static final TypedElementInfo __close = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("close") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class, Map.of("value", ""))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodX = TypedElementInfo.builder() - .typeName(create(long.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodX") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodX__p1 = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("p1") - .build(); - private static final TypedElementInfo __methodX__p2 = TypedElementInfo.builder() - .typeName(create(int.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("p2") - .build(); - private static final TypedElementInfo __methodX__p3 = TypedElementInfo.builder() - .typeName(create(boolean.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("p3") - .build(); - private static final TypedElementInfo __methodY = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodY") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodZ = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodZ") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __throwRuntimeException = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("throwRuntimeException") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedX"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.inject.interceptor.TestNamed.class, Map.of("value", "TestNamed-ClassX"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - - private static final TypeName __serviceTypeName = TypeName.create(io.helidon.inject.tests.inject.interceptor.XImpl.class); - - private final Provider __provider; - private final ServiceProvider __sp; - private final io.helidon.inject.tests.inject.interceptor.XImpl __impl; - private final List> __methodIA1__interceptors; - private final List> __methodIA2__interceptors; - private final List> __methodIB__interceptors; - private final List> __methodIB2__interceptors; - private final List> __close__interceptors; - private final List> __methodX__interceptors; - private final List> __methodY__interceptors; - private final List> __methodZ__interceptors; - private final List> __throwRuntimeException__interceptors; - private final InterceptedMethod __methodIA1__call; - private final InterceptedMethod __methodIA2__call; - private final InterceptedMethod __methodIB__call; - private final InterceptedMethod __methodIB2__call; - private final InterceptedMethod __close__call; - private final InterceptedMethod __methodX__call; - private final InterceptedMethod __methodY__call; - private final InterceptedMethod __methodZ__call; - private final InterceptedMethod __throwRuntimeException__call; - - @Inject - @SuppressWarnings("unchecked") - XImpl$$Injection$$Interceptor( - @ClassNamed(io.helidon.inject.tests.inject.interceptor.TestNamed.class) List> io_helidon_inject_tests_inject_interceptor_TestNamed, - @ClassNamed(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class) List> io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno, - Provider provider) { - this.__provider = Objects.requireNonNull(provider); - this.__sp = (provider instanceof ServiceProvider) ? (ServiceProvider) __provider : null; - List> __ctor__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed); - this.__methodIA1__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed); - this.__methodIA2__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed, io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno); - this.__methodIB__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed, io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno); - this.__methodIB2__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed, io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno); - this.__close__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed, io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno); - this.__methodX__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed); - this.__methodY__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed); - this.__methodZ__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed); - this.__throwRuntimeException__interceptors = mergeAndCollapse(io_helidon_inject_tests_inject_interceptor_TestNamed); - - Function call = args -> __provider.get(); - io.helidon.inject.tests.inject.interceptor.XImpl result = createInvokeAndSupply( - InvocationContext.builder() - .serviceProvider(__sp) - .serviceTypeName(__serviceTypeName) - .classAnnotations(__serviceLevelAnnotations) - .elementInfo(__ctor) - .interceptors(__ctor__interceptors) - .build(), - call, - new Object[0]); - this.__impl = Objects.requireNonNull(result); - - this.__methodIA1__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodIA1__interceptors, __methodIA1) { - @Override - public java.lang.Void invoke(Object... args) throws Throwable { - impl().methodIA1(); - return null; - } - }; - - this.__methodIA2__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodIA2__interceptors, __methodIA2) { - @Override - public java.lang.Void invoke(Object... args) throws Throwable { - impl().methodIA2(); - return null; - } - }; - - this.__methodIB__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodIB__interceptors, __methodIB, - List.of(__methodIB__p1)) { - @Override - public java.lang.Void invoke(Object... args) throws Throwable { - impl().methodIB((java.lang.String) args[0]); - return null; - } - }; - - this.__methodIB2__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodIB2__interceptors, __methodIB2, - List.of(__methodIB2__p1)) { - @Override - public java.lang.String invoke(Object... args) throws Throwable { - return impl().methodIB2((java.lang.String) args[0]); - } - }; - - this.__close__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __close__interceptors, __close) { - @Override - public java.lang.Void invoke(Object... args) throws Throwable { - impl().close(); - return null; - } - }; - - this.__methodX__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodX__interceptors, __methodX, - List.of(__methodX__p1, __methodX__p2, __methodX__p3)) { - @Override - public java.lang.Long invoke(Object... args) throws Throwable { - return impl().methodX((java.lang.String) args[0], (java.lang.Integer) args[1], (java.lang.Boolean) args[2]); - } - }; - - this.__methodY__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodY__interceptors, __methodY) { - @Override - public java.lang.String invoke(Object... args) throws Throwable { - return impl().methodY(); - } - }; - - this.__methodZ__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodZ__interceptors, __methodZ) { - @Override - public java.lang.String invoke(Object... args) throws Throwable { - return impl().methodZ(); - } - }; - - this.__throwRuntimeException__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __throwRuntimeException__interceptors, __throwRuntimeException) { - @Override - public java.lang.Void invoke(Object... args) throws Throwable { - impl().throwRuntimeException(); - return null; - } - }; - } - - @Override - public void methodIA1() { - Object[] args = new Object[] { }; - createInvokeAndSupply(__methodIA1__call.ctx(), __interceptedArgs -> __methodIA1__call.apply(__interceptedArgs), args); - } - - @Override - public void methodIA2() { - Object[] args = new Object[] { }; - createInvokeAndSupply(__methodIA2__call.ctx(), __interceptedArgs -> __methodIA2__call.apply(__interceptedArgs), args); - } - - @Override - public void methodIB(java.lang.String p1) { - Object[] args = new Object[] { p1 }; - createInvokeAndSupply(__methodIB__call.ctx(), __interceptedArgs -> __methodIB__call.apply(__interceptedArgs), args); - } - - @Override - public java.lang.String methodIB2(java.lang.String p1) { - Object[] args = new Object[] { p1 }; - return createInvokeAndSupply(__methodIB2__call.ctx(), __interceptedArgs -> __methodIB2__call.apply(__interceptedArgs), args); - } - - @Override - public void close() throws java.io.IOException, java.lang.RuntimeException { - Object[] args = new Object[] { }; - createInvokeAndSupply(__close__call.ctx(), __interceptedArgs -> __close__call.apply(__interceptedArgs), args); - } - - @Override - public long methodX(java.lang.String p1, int p2, boolean p3) throws java.io.IOException, java.lang.RuntimeException, java.lang.AssertionError { - Object[] args = new Object[] { p1, p2, p3 }; - return createInvokeAndSupply(__methodX__call.ctx(), __interceptedArgs -> __methodX__call.apply(__interceptedArgs), args); - } - - @Override - public java.lang.String methodY() { - Object[] args = new Object[] { }; - return createInvokeAndSupply(__methodY__call.ctx(), __interceptedArgs -> __methodY__call.apply(__interceptedArgs), args); - } - - @Override - public java.lang.String methodZ() { - Object[] args = new Object[] { }; - return createInvokeAndSupply(__methodZ__call.ctx(), __interceptedArgs -> __methodZ__call.apply(__interceptedArgs), args); - } - - @Override - public void throwRuntimeException() { - Object[] args = new Object[] { }; - createInvokeAndSupply(__throwRuntimeException__call.ctx(), __interceptedArgs -> __throwRuntimeException__call.apply(__interceptedArgs), args); - } - -} diff --git a/inject/tests/resources-inject/src/test/resources/expected/yimpl-interceptor._java_ b/inject/tests/resources-inject/src/test/resources/expected/yimpl-interceptor._java_ deleted file mode 100644 index a6e932b7201..00000000000 --- a/inject/tests/resources-inject/src/test/resources/expected/yimpl-interceptor._java_ +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) #DATE# Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package io.helidon.inject.tests.inject.interceptor; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.common.types.TypeValues; -import io.helidon.inject.api.ClassNamed; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.runtime.InterceptedMethod; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -import static io.helidon.common.types.TypeName.create; -import static io.helidon.inject.runtime.Invocation.createInvokeAndSupply; -import static io.helidon.inject.runtime.Invocation.mergeAndCollapse; - -/** - * Injection {@link Interceptor} for {@link io.helidon.inject.tests.inject.interceptor.YImpl }. - */ -// using the interfaces approach -@io.helidon.common.Weight(100.001) -@io.helidon.inject.api.Intercepted(io.helidon.inject.tests.inject.interceptor.YImpl.class) -@Singleton -@SuppressWarnings("ALL") -@io.helidon.common.Generated(value = "io.helidon.inject.tools.InterceptorCreatorDefault", trigger = "io.helidon.inject.tests.inject.interceptor.YImpl") -public class YImpl$$Injection$$Interceptor /* extends io.helidon.inject.tests.inject.interceptor.YImpl */ implements io.helidon.inject.tests.plain.interceptor.IB, java.io.Closeable, java.lang.AutoCloseable { - private static final List __serviceLevelAnnotations = List.of( - Annotation.create(jakarta.inject.Singleton.class), - Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedY")), - Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable"))), - Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))); - - private static final TypedElementInfo __ctor = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_CONSTRUCTOR) - .elementName(io.helidon.inject.api.ElementInfo.CONSTRUCTOR) - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedY"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(jakarta.inject.Inject.class)) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIB = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodIB") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedY"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class, Map.of("value", "IBSubAnno"))) - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "methodIB"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIB__p1 = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("p1") - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "arg1"))) - .build(); - private static final TypedElementInfo __methodIB2 = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("methodIB2") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedY"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class, Map.of("value", "IBSubAnno"))) - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "methodIB2"))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - private static final TypedElementInfo __methodIB2__p1 = TypedElementInfo.builder() - .typeName(create(java.lang.String.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("p1") - .addAnnotation(Annotation.create(jakarta.inject.Named.class, Map.of("value", "arg1"))) - .build(); - private static final TypedElementInfo __close = TypedElementInfo.builder() - .typeName(create(void.class)) - .elementTypeKind(TypeValues.KIND_METHOD) - .elementName("close") - .addAnnotation(Annotation.create(io.helidon.inject.api.ClassNamed.class, Map.of("value", "io.helidon.inject.tests.inject.ClassNamedY"))) - .addAnnotation(Annotation.create(io.helidon.inject.api.ExternalContracts.class, Map.of("moduleNames", java.util.List.of("test1", "test2"), "value", java.util.List.of("java.io.Closeable")))) - .addAnnotation(Annotation.create(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class, Map.of("value", ""))) - .addAnnotation(Annotation.create(jakarta.inject.Singleton.class)) - .addAnnotation(Annotation.create(java.lang.Override.class)) - .addAnnotation(Annotation.create(java.lang.SuppressWarnings.class, Map.of("value", java.util.List.of("unused")))) - .build(); - - private static final TypeName __serviceTypeName = TypeName.create(io.helidon.inject.tests.inject.interceptor.YImpl.class); - - private final Provider __provider; - private final ServiceProvider __sp; - private final io.helidon.inject.tests.inject.interceptor.YImpl __impl; - private final List> __methodIB__interceptors; - private final List> __methodIB2__interceptors; - private final List> __close__interceptors; - private final InterceptedMethod __methodIB__call; - private final InterceptedMethod __methodIB2__call; - private final InterceptedMethod __close__call; - - @Inject - @SuppressWarnings("unchecked") - YImpl$$Injection$$Interceptor( - @ClassNamed(io.helidon.inject.tests.plain.interceptor.InterceptorBasedAnno.class) List> io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno, - Provider provider) { - this.__provider = Objects.requireNonNull(provider); - this.__sp = (provider instanceof ServiceProvider) ? (ServiceProvider) __provider : null; - List> __ctor__interceptors = mergeAndCollapse(); - this.__methodIB__interceptors = mergeAndCollapse(io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno); - this.__methodIB2__interceptors = mergeAndCollapse(io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno); - this.__close__interceptors = mergeAndCollapse(io_helidon_inject_tests_plain_interceptor_InterceptorBasedAnno); - - Function call = args -> __provider.get(); - io.helidon.inject.tests.inject.interceptor.YImpl result = createInvokeAndSupply( - InvocationContext.builder() - .serviceProvider(__sp) - .serviceTypeName(__serviceTypeName) - .classAnnotations(__serviceLevelAnnotations) - .elementInfo(__ctor) - .interceptors(__ctor__interceptors) - .build(), - call, - new Object[0]); - this.__impl = Objects.requireNonNull(result); - - this.__methodIB__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodIB__interceptors, __methodIB, - List.of(__methodIB__p1)) { - @Override - public java.lang.Void invoke(Object... args) throws Throwable { - impl().methodIB((java.lang.String) args[0]); - return null; - } - }; - - this.__methodIB2__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __methodIB2__interceptors, __methodIB2, - List.of(__methodIB2__p1)) { - @Override - public java.lang.String invoke(Object... args) throws Throwable { - return impl().methodIB2((java.lang.String) args[0]); - } - }; - - this.__close__call = new InterceptedMethod( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __close__interceptors, __close) { - @Override - public java.lang.Void invoke(Object... args) throws Throwable { - impl().close(); - return null; - } - }; - } - - @Override - public void methodIB(java.lang.String p1) { - Object[] args = new Object[] { p1 }; - createInvokeAndSupply(__methodIB__call.ctx(), __interceptedArgs -> __methodIB__call.apply(__interceptedArgs), args); - } - - @Override - public java.lang.String methodIB2(java.lang.String p1) { - Object[] args = new Object[] { p1 }; - return createInvokeAndSupply(__methodIB2__call.ctx(), __interceptedArgs -> __methodIB2__call.apply(__interceptedArgs), args); - } - - @Override - public void close() throws java.io.IOException, java.lang.RuntimeException { - Object[] args = new Object[] { }; - createInvokeAndSupply(__close__call.ctx(), __interceptedArgs -> __close__call.apply(__interceptedArgs), args); - } - -} diff --git a/inject/tests/resources-plain/pom.xml b/inject/tests/resources-plain/pom.xml deleted file mode 100644 index d9d01aa101b..00000000000 --- a/inject/tests/resources-plain/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - io.helidon.inject.tests - helidon-inject-tests-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-tests-resources-plain - Helidon Injection Test Plain Resources - a jar that offers contracts and other artifacts but is not a native injection module (e.g., no injection APT). - - - - - io.helidon.inject - helidon-inject-api - - - jakarta.inject - jakarta.inject-api - provided - - - jakarta.annotation - jakarta.annotation-api - provided - - - - diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/Hello.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/Hello.java deleted file mode 100644 index 687fc05b168..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/Hello.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.hello; - -import io.helidon.inject.api.Contract; - -@Contract -public interface Hello { - - void sayHello(); - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/HelloImpl.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/HelloImpl.java deleted file mode 100644 index c8c75403df8..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/HelloImpl.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.hello; - -import java.util.List; -import java.util.Optional; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@Singleton -@Weight(Weighted.DEFAULT_WEIGHT) -public class HelloImpl implements Hello { - - @Inject - World world; - - @Inject - Provider worldRef; - - @Inject - List> listOfWorldRefs; - - @Inject - List listOfWorlds; - - @Inject @Named("red") - Optional redWorld; - - @Inject - private Optional privateWorld; - - private World setWorld; - private Optional setRedWorld; - private World ctorWorld; - - int postConstructCallCount; - int preDestroyCallCount; - - HelloImpl() { - } - - @Inject - public HelloImpl(World ctorWorld) { - this(); - this.ctorWorld = ctorWorld; - } - - @Override - public void sayHello() { - assert (postConstructCallCount == 1); - assert (preDestroyCallCount == 0); - System.getLogger(getClass().getName()).log(System.Logger.Level.INFO, "hello {0}", worldRef.get()); - assert (world == worldRef.get()) : "world != worldRef"; - assert (world == setWorld) : "world != setWorld"; - assert (ctorWorld == world) : "world != ctorWorld"; - } - - @Inject - public void world(World world) { - this.setWorld = world; - assert (world == ctorWorld); - } - - @Inject - public void setRedWorld(@Named("red") Optional redWorld) { - this.setRedWorld = redWorld; - } - - @PostConstruct - public void postConstruct() { - postConstructCallCount++; - } - - @PreDestroy - public void preDestroy() { - preDestroyCallCount++; - } - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/MyTestQualifier.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/MyTestQualifier.java deleted file mode 100644 index d70280f74c6..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/MyTestQualifier.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.hello; - -import java.lang.annotation.Documented; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import jakarta.inject.Qualifier; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; - -/** - * Explicitly intended to test compile time scope w/ inheritance of annotations. - */ -@Documented -@Inherited -@Qualifier -@Retention(RetentionPolicy.CLASS) -@Target({TYPE, METHOD, PARAMETER, CONSTRUCTOR}) -public @interface MyTestQualifier { - - /** - * @return the name - */ - String value() default ""; - - /** - * @return just for testing - */ - String[] extendedValue() default ""; - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/SomeOtherLocalNonContractInterface2.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/SomeOtherLocalNonContractInterface2.java deleted file mode 100644 index 925f60bf868..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/SomeOtherLocalNonContractInterface2.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.hello; - -public interface SomeOtherLocalNonContractInterface2 { - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/World.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/World.java deleted file mode 100644 index 9971f7d47c2..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/World.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.hello; - -@FunctionalInterface -public interface World { - - String name(); - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/WorldImpl.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/WorldImpl.java deleted file mode 100644 index c6452c3ef41..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/hello/WorldImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.hello; - -import java.io.Serializable; - -import io.helidon.inject.api.ExternalContracts; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@ExternalContracts(value = World.class, moduleNames = "AnotherModule") -@Named("unknown") -@Singleton -public class WorldImpl implements World, SomeOtherLocalNonContractInterface2, Serializable { - private final String name; - - WorldImpl() { - this("unknown"); - } - - WorldImpl(String name) { - this.name = name; - } - - @Override - public String name() { - return name; - } -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/IA.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/IA.java deleted file mode 100644 index 060d6098147..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/IA.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.interceptor; - -import io.helidon.inject.api.Contract; - -@Contract -public interface IA { - - void methodIA1(); - - void methodIA2(); - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/IB.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/IB.java deleted file mode 100644 index 062b8077728..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/IB.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.interceptor; - -@InterceptorBasedAnno("IBAnno") -public interface IB { - - void methodIB(String val); - - String methodIB2(String val); - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/InterceptorBasedAnno.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/InterceptorBasedAnno.java deleted file mode 100644 index f55756f80fd..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/InterceptorBasedAnno.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.interceptor; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import io.helidon.inject.api.InterceptedTrigger; - -@InterceptedTrigger -@Retention(RetentionPolicy.CLASS) -public @interface InterceptorBasedAnno { - - String value() default ""; - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/TestNamedInterceptor.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/TestNamedInterceptor.java deleted file mode 100644 index 636d1234415..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/TestNamedInterceptor.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.interceptor; - -import java.util.concurrent.atomic.AtomicInteger; - -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationContext; - -import static io.helidon.common.types.TypeNames.PRIMITIVE_LONG; -import static io.helidon.common.types.TypeNames.STRING; - -@SuppressWarnings({"ALL", "unchecked"}) -public class TestNamedInterceptor implements Interceptor { - public static final AtomicInteger ctorCount = new AtomicInteger(); - - public TestNamedInterceptor() { - ctorCount.incrementAndGet(); - } - - @Override - public V proceed(InvocationContext ctx, - Chain chain, - Object... args) { - assert (ctx != null); - - TypedElementInfo methodInfo = ctx.elementInfo(); - if (methodInfo != null && methodInfo.typeName().equals(PRIMITIVE_LONG)) { - V result = chain.proceed(args); - long longResult = (Long) result; - Object interceptedResult = (longResult * 2); - return (V) interceptedResult; - } else if (methodInfo != null && methodInfo.typeName().equals(STRING)) { - V result = chain.proceed(args); - return (V) ("intercepted:" + result); - } else { - return chain.proceed(args); - } - } - -} diff --git a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/X.java b/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/X.java deleted file mode 100644 index f6c1a2de40c..00000000000 --- a/inject/tests/resources-plain/src/main/java/io/helidon/inject/tests/plain/interceptor/X.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.plain.interceptor; - -import java.io.Closeable; -import java.io.IOException; -import java.util.Optional; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Singleton -@Named("ClassX") -public class X implements IA, IB, Closeable { - - X() { - // this is the one that will be used by interception - } - - @Inject - public X(Optional optionalIA) { - assert (optionalIA.isEmpty()); - } - - @Override - public void methodIA1() { - } - - @InterceptorBasedAnno("IA2") - @Override - public void methodIA2() { - } - - @Named("methodIB2") - @InterceptorBasedAnno("IBSubAnno") - @Override - public String methodIB2(@Named("arg1") String val) { - return val; - } - - @Named("methodIB") - @InterceptorBasedAnno("IBSubAnno") - @Override - public void methodIB(@Named("arg1") String val) { - } - - @InterceptorBasedAnno - @Override - public void close() throws IOException, RuntimeException { - throw new IOException("forced"); - } - - public long methodX(String arg1, int arg2, boolean arg3) throws IOException, RuntimeException, AssertionError { - return 101; - } - - // test of package private - String methodY() { - return "methodY"; - } - - // test of protected - protected String methodZ() { - return "methodZ"; - } - - // test of protected - protected void throwRuntimeException() { - throw new RuntimeException("forced"); - } - -} diff --git a/inject/tests/resources-plain/src/main/java/module-info.java b/inject/tests/resources-plain/src/main/java/module-info.java deleted file mode 100644 index be8e3d07241..00000000000 --- a/inject/tests/resources-plain/src/main/java/module-info.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Plain Test Resources. - */ -module io.helidon.inject.tests.plain { - requires static jakarta.inject; - requires static jakarta.annotation; - - requires io.helidon.common.types; - requires io.helidon.common; - requires io.helidon.inject.api; - - exports io.helidon.inject.tests.plain.hello; - exports io.helidon.inject.tests.plain.interceptor; - -} diff --git a/inject/tests/runtime/pom.xml b/inject/tests/runtime/pom.xml deleted file mode 100644 index 1b96d26567b..00000000000 --- a/inject/tests/runtime/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - io.helidon.inject.tests - helidon-inject-tests-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-tests-runtime - Helidon Injection Tests Runtime - - Test Injection runtime to remove dependency on Helidon Config, which did not allow us to have services in config. - - - - - io.helidon.inject - helidon-inject-runtime - - - jakarta.annotation - jakarta.annotation-api - - - io.helidon.config - helidon-config - test - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionPlansTest.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionPlansTest.java deleted file mode 100644 index 8e4b4709d02..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionPlansTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.io.Closeable; -import java.util.List; -import java.util.Map; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceBinder; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.inject.api.Qualifier.createNamed; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; - -class DefaultInjectionPlansTest { - static final FakeInjectionPointProviderActivator sp1 = new FakeInjectionPointProviderActivator(); - static final FakeRegularActivator sp2 = new FakeRegularActivator(); - - Config config = Config.builder( - ConfigSources.create( - Map.of("inject.permits-dynamic", "true"), "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - - @BeforeEach - void init() { - InjectionServices.globalBootstrap(Bootstrap.builder().config(config).build()); - } - - @AfterEach - void tearDown() { - SimpleInjectionTestingSupport.resetAll(); - } - - /** - * Also exercised in examples/inject. - */ - @Test - void testInjectionPointResolversFor() { - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - DefaultServices services = (DefaultServices) InjectionServices.realizedServices(); - services.bind(injectionServices, new FakeModuleComponent(), true); - - ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addQualifier(createNamed("whatever")) - .addContractImplemented(Closeable.class) - .build(); - List result = DefaultInjectionPlans.injectionPointProvidersFor(services, criteria).stream() - .map(ServiceProvider::description).toList(); - assertThat(result, - contains(sp1.description())); - } - - static class FakeModuleComponent implements ModuleComponent { - @Override - public void configure(ServiceBinder binder) { - binder.bind(sp1); - binder.bind(sp2); - } - } - - static class FakeInjectionPointProviderActivator extends AbstractServiceProvider { - private static final ServiceInfo serviceInfo = - ServiceInfo.builder() - .serviceTypeName(FakeInjectionPointProviderActivator.class) - .addContractImplemented(Closeable.class) - .addExternalContractImplemented(InjectionPointProvider.class) - .addExternalContractImplemented(jakarta.inject.Provider.class) - .build(); - - public FakeInjectionPointProviderActivator() { - serviceInfo(serviceInfo); - } - - @Override - public Class serviceType() { - return Closeable.class; - } - } - - static class FakeRegularActivator extends AbstractServiceProvider { - private static final ServiceInfo serviceInfo = - ServiceInfo.builder() - .serviceTypeName(FakeRegularActivator.class) - .addContractImplemented(Closeable.class) - .addExternalContractImplemented(jakarta.inject.Provider.class) - .build(); - - public FakeRegularActivator() { - serviceInfo(serviceInfo); - } - - @Override - public Class serviceType() { - return Closeable.class; - } - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesTest.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesTest.java deleted file mode 100644 index 71443454e1d..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.Map; -import java.util.Objects; - -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.runtime.testsubjects.HelloInjection$$Application; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalPresent; -import static org.hamcrest.MatcherAssert.assertThat; - -class DefaultInjectionServicesTest { - - @BeforeEach - void setUp() { - tearDown(); - Config config = Config.builder( - ConfigSources.create( - Map.of("inject.permits-dynamic", "true"), "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - InjectionServices.globalBootstrap(Bootstrap.builder().config(config).build()); - } - - @AfterEach - void tearDown() { - HelloInjection$$Application.ENABLED = true; - SimpleInjectionTestingSupport.resetAll(); - } - - @Test - void realizedServices() { - assertThat(InjectionServices.unrealizedServices(), optionalEmpty()); - - Objects.requireNonNull(InjectionServices.realizedServices()); - assertThat(InjectionServices.unrealizedServices(), optionalPresent()); - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/HelloInjectionWorldSanityTest.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/HelloInjectionWorldSanityTest.java deleted file mode 100644 index fbe7f4a90c3..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/HelloInjectionWorldSanityTest.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.common.Weighted; -import io.helidon.common.types.TypeName; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.api.ActivationRequest; -import io.helidon.inject.api.ActivationResult; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.DeActivationRequest; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Injector; -import io.helidon.inject.api.InjectorOptions; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Phase; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.runtime.testsubjects.HelloInjection$$Application; -import io.helidon.inject.runtime.testsubjects.HelloInjectionImpl$$injectionActivator; -import io.helidon.inject.runtime.testsubjects.HelloInjectionWorld; -import io.helidon.inject.runtime.testsubjects.HelloInjectionWorldImpl; -import io.helidon.inject.runtime.testsubjects.InjectionWorld; -import io.helidon.inject.runtime.testsubjects.InjectionWorldImpl; -import io.helidon.inject.runtime.testsubjects.InjectionWorldImpl$$injectionActivator; -import io.helidon.inject.spi.InjectionPlan; - -import jakarta.inject.Singleton; -import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.sameInstance; - -/** - * Sanity type tests only. The "real" testing is in the tests submodules. - */ -class HelloInjectionWorldSanityTest { - private static final int EXPECTED_MODULES = 2; - - @BeforeEach - void setUp() { - tearDown(); - Config config = Config.builder( - ConfigSources.create( - Map.of("inject.permits-dynamic", "true"), "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - InjectionServices.globalBootstrap(Bootstrap.builder().config(config).build()); - } - - @AfterEach - void tearDown() { - HelloInjection$$Application.ENABLED = true; - SimpleInjectionTestingSupport.resetAll(); - } - - @Test - void sanity() { - Services services = InjectionServices.realizedServices(); - - List> moduleProviders = services.lookupAll(ModuleComponent.class); - assertThat(moduleProviders.size(), - equalTo(EXPECTED_MODULES)); - List descriptions = ServiceUtils.toDescriptions(moduleProviders); - assertThat(descriptions, - containsInAnyOrder("EmptyModule:ACTIVE", "HelloInjection$$Module:ACTIVE")); - - List> applications = services.lookupAll(Application.class); - assertThat(applications.size(), - equalTo(1)); - assertThat(ServiceUtils.toDescriptions(applications), - containsInAnyOrder("HelloInjection$$Application:ACTIVE")); - } - - @Test - void standardActivationWithNoApplicationEnabled() { - HelloInjection$$Application.ENABLED = false; - Optional injectionServices = InjectionServices.injectionServices(); - ((DefaultInjectionServices) injectionServices.orElseThrow()).reset(true); - - standardActivation(); - } - - @Test - void standardActivation() { - Services services = InjectionServices.realizedServices(); - - ServiceProvider helloProvider1 = services.lookup(HelloInjectionWorld.class); - assertThat(helloProvider1, - notNullValue()); - - ServiceProvider helloProvider2 = services.lookup(HelloInjectionWorldImpl.class); - assertThat(helloProvider1, - sameInstance(helloProvider2)); - assertThat(helloProvider1.id(), - equalTo(HelloInjectionWorldImpl.class.getName())); - assertThat(helloProvider1.currentActivationPhase(), - equalTo(Phase.INIT)); - assertThat(helloProvider1.description(), - equalTo(HelloInjectionWorldImpl.class.getSimpleName() + ":" + Phase.INIT)); - - ServiceInfo serviceInfo = helloProvider1.serviceInfo(); - assertThat(serviceInfo.serviceTypeName(), - equalTo(TypeName.create(HelloInjectionWorldImpl.class))); - assertThat(serviceInfo.contractsImplemented(), - containsInAnyOrder(TypeName.create(HelloInjectionWorld.class))); - assertThat(serviceInfo.externalContractsImplemented().size(), - equalTo(0)); - assertThat(serviceInfo.scopeTypeNames(), - containsInAnyOrder(TypeName.create(Singleton.class))); - assertThat(serviceInfo.qualifiers().size(), - equalTo(0)); - assertThat(serviceInfo.activatorTypeName().orElseThrow(), - equalTo(TypeName.create(HelloInjectionImpl$$injectionActivator.class))); - assertThat(serviceInfo.declaredRunLevel(), - optionalValue(equalTo(0))); - assertThat(serviceInfo.realizedRunLevel(), - equalTo(0)); - assertThat(serviceInfo.moduleName(), - optionalValue(equalTo("example"))); - assertThat(serviceInfo.declaredWeight(), - optionalEmpty()); - assertThat(serviceInfo.realizedWeight(), - equalTo(Weighted.DEFAULT_WEIGHT)); - - ServiceProvider worldProvider1 = services.lookup(InjectionWorld.class); - assertThat(worldProvider1, notNullValue()); - assertThat(worldProvider1.description(), - equalTo("InjectionWorldImpl:INIT")); - - // now activate - HelloInjectionWorld hello1 = helloProvider1.get(); - MatcherAssert.assertThat(hello1.sayHello(), - equalTo("Hello inject")); - assertThat(helloProvider1.currentActivationPhase(), - equalTo(Phase.ACTIVE)); - assertThat(helloProvider1.description(), - equalTo("HelloInjectionWorldImpl:ACTIVE")); - - // world should be active now too, since Hello should have implicitly activated it - assertThat(worldProvider1.description(), - equalTo("InjectionWorldImpl:ACTIVE")); - - // check the post construct counts - MatcherAssert.assertThat(((HelloInjectionWorldImpl) helloProvider1.get()).postConstructCallCount(), - equalTo(1)); - MatcherAssert.assertThat(((HelloInjectionWorldImpl) helloProvider1.get()).preDestroyCallCount(), - equalTo(0)); - - // deactivate just the Hello service - ActivationResult result = helloProvider1.deActivator().orElseThrow() - .deactivate(DeActivationRequest.create()); - assertThat(result.finished(), - is(true)); - assertThat(result.success(), - is(true)); - assertThat(result.serviceProvider(), - sameInstance(helloProvider2)); - assertThat(result.finishingActivationPhase(), - is(Phase.DESTROYED)); - assertThat(result.startingActivationPhase(), - is(Phase.ACTIVE)); - assertThat(helloProvider1.description(), - equalTo("HelloInjectionWorldImpl:DESTROYED")); - MatcherAssert.assertThat(((HelloInjectionWorldImpl) hello1).postConstructCallCount(), - equalTo(1)); - MatcherAssert.assertThat(((HelloInjectionWorldImpl) hello1).preDestroyCallCount(), - equalTo(1)); - assertThat(worldProvider1.description(), - equalTo("InjectionWorldImpl:ACTIVE")); - } - - @Test - void viaInjector() { - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - Injector injector = injectionServices.injector().orElseThrow(); - - HelloInjectionImpl$$injectionActivator subversiveWay = new HelloInjectionImpl$$injectionActivator(); - subversiveWay.injectionServices(Optional.of(injectionServices)); - - ActivationResult result = injector.activateInject(subversiveWay, InjectorOptions.builder().build()); - assertThat(result.finished(), is(true)); - assertThat(result.success(), is(true)); - - HelloInjectionWorld hello1 = subversiveWay.serviceRef().orElseThrow(); - MatcherAssert.assertThat(hello1.sayHello(), - equalTo("Hello inject")); - MatcherAssert.assertThat(subversiveWay.currentActivationPhase(), - equalTo(Phase.ACTIVE)); - - MatcherAssert.assertThat(hello1, - sameInstance(subversiveWay.get())); - assertThat(subversiveWay, sameInstance(result.serviceProvider())); - - // the above is subversive because it is disconnected from the "real" activator - Services services = injectionServices.services(); - ServiceProvider realHelloProvider = - ((DefaultServices) services).serviceProviderFor(TypeName.create(HelloInjectionWorldImpl.class)); - assertThat(subversiveWay, not(sameInstance(realHelloProvider))); - - assertThat(realHelloProvider.currentActivationPhase(), - equalTo(Phase.INIT)); - - result = injector.deactivate(subversiveWay, InjectorOptions.builder().build()); - assertThat(result.success(), is(true)); - } - - @Test - void injectionPlanResolved() { - HelloInjectionImpl$$injectionActivator activator = new HelloInjectionImpl$$injectionActivator(); - activator.injectionServices(InjectionServices.injectionServices()); - - ActivationResult result = activator.activate(ActivationRequest.builder().targetPhase(Phase.INJECTING).build()); - assertThat(result.success(), is(true)); - - MatcherAssert.assertThat(activator.currentActivationPhase(), is(Phase.INJECTING)); - MatcherAssert.assertThat(activator.serviceRef().orElseThrow().postConstructCallCount(), equalTo(0)); - MatcherAssert.assertThat(activator.serviceRef().orElseThrow().preDestroyCallCount(), equalTo(0)); - - Map injectionPlan = result.injectionPlans(); - assertThat(injectionPlan.keySet(), containsInAnyOrder( - "io.helidon.inject.runtime.testsubjects.world", - "io.helidon.inject.runtime.testsubjects.worldRef", - "io.helidon.inject.runtime.testsubjects.redWorld", - "io.helidon.inject.runtime.testsubjects.listOfWorlds", - "io.helidon.inject.runtime.testsubjects.listOfWorldRefs", - "io.helidon.inject.runtime.testsubjects.world|1(1)")); - InjectionPlan plan = injectionPlan.get("io.helidon.inject.runtime.testsubjects.world"); - assertThat(plan.wasResolved(), is(true)); - assertThat(plan.resolved().orElseThrow().getClass(), equalTo(InjectionWorldImpl.class)); - plan = injectionPlan.get("io.helidon.inject.runtime.testsubjects.redWorld"); - assertThat(plan.wasResolved(), is(true)); - assertThat(plan.resolved().orElseThrow().getClass(), equalTo(Optional.class)); - plan = injectionPlan.get("io.helidon.inject.runtime.testsubjects.worldRef"); - assertThat(plan.wasResolved(), is(true)); - assertThat(plan.resolved().orElseThrow().getClass(), equalTo(InjectionWorldImpl$$injectionActivator.class)); - plan = injectionPlan.get("io.helidon.inject.runtime.testsubjects.listOfWorlds"); - assertThat(plan.wasResolved(), is(true)); - assertThat(plan.resolved().orElseThrow().getClass(), equalTo(ArrayList.class)); - - Map resolutions = result.resolvedDependencies(); - assertThat(resolutions.size(), equalTo(injectionPlan.size())); - - // now take us through activation - result = activator.activate(ActivationRequest.builder() - .startingPhase(activator.currentActivationPhase()) - .build()); - assertThat(result.success(), is(true)); - MatcherAssert.assertThat(activator.currentActivationPhase(), is(Phase.ACTIVE)); - MatcherAssert.assertThat(activator.serviceRef().orElseThrow().postConstructCallCount(), equalTo(1)); - MatcherAssert.assertThat(activator.serviceRef().orElseThrow().preDestroyCallCount(), equalTo(0)); - - // these should have happened prior, so not there any longer - assertThat(result.injectionPlans(), equalTo(Map.of())); - assertThat(result.resolvedDependencies(), equalTo(Map.of())); - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/LockContentionTest.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/LockContentionTest.java deleted file mode 100644 index c824ed8a8cd..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/LockContentionTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import io.helidon.common.types.TypeName; -import io.helidon.config.Config; -import io.helidon.config.ConfigSources; -import io.helidon.inject.api.ActivationResult; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Services; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.fail; - -class LockContentionTest { - final int COUNT = 100; - - final ExecutorService es = Executors.newFixedThreadPool(16); - final Config config = Config.builder( - ConfigSources.create( - Map.of("inject.permits-dynamic", "true"), "config-1")) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - - @BeforeEach - void init() { - InjectionServices.globalBootstrap(Bootstrap.builder().config(config).build()); - } - - @AfterEach - void tearDown() { - SimpleInjectionTestingSupport.resetAll(); - } - - @Test - // we cannot interlace shutdown with startups here - so instead we are checking to ensure N threads can call startup - // and then N threads can call shutdown in parallel, but in phases - void lockContention() { - Map> result = new ConcurrentHashMap<>(); - for (int i = 1; i <= COUNT; i++) { - result.put("start run:" + i, es.submit(this::start)); - } - - verify(result); - result.clear(); - - for (int i = 1; i <= COUNT; i++) { - result.put("shutdown run:" + i, es.submit(this::shutdown)); - } - - verify(result); - } - - void verify(Map> result) { - result.forEach((k, v) -> { - try { - assertThat(k, v.get(), notNullValue()); - } catch (Exception e) { - fail("failed on " + k, e); - } - }); - } - - Services start() { - return Objects.requireNonNull(InjectionServices.realizedServices()); - } - - Map shutdown() { - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - Map result = new LinkedHashMap<>(); - Map round; - do { - round = injectionServices.shutdown().orElseThrow(); - result.putAll(round); - } while (!round.isEmpty()); - return result; - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/SimpleInjectionTestingSupport.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/SimpleInjectionTestingSupport.java deleted file mode 100644 index 39d3da2c4f2..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/SimpleInjectionTestingSupport.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime; - -import io.helidon.inject.api.InjectionServicesHolder; - -/** - * Supporting helper utilities unit-testing services. - */ -class SimpleInjectionTestingSupport { - - /** - * Resets all internal configuration instances, JVM global singletons, service registries, etc. - */ - static void resetAll() { - Holder.reset(); - } - - - @SuppressWarnings("deprecation") - private static class Holder extends InjectionServicesHolder { - public static void reset() { - InjectionServicesHolder.reset(); - } - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/EmptyModule.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/EmptyModule.java deleted file mode 100644 index f6a0a0c2e0c..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/EmptyModule.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceBinder; - -import jakarta.inject.Singleton; - -/** - * For testing. - */ -@Singleton -public final class EmptyModule implements ModuleComponent { - - @Override - public void configure(ServiceBinder binder) { - - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjection$$Application.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjection$$Application.java deleted file mode 100644 index d74f2ee3982..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjection$$Application.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import java.util.Optional; - -import io.helidon.common.Generated; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.ServiceInjectionPlanBinder; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -/** - * For testing. - */ -@Generated(value = "example", comments = "API Version: n", trigger = "io.helidon.inject.tools.ApplicationCreatorDefault") -@Singleton -@Named(HelloInjection$$Application.NAME) -public class HelloInjection$$Application implements Application { - public static boolean ENABLED = true; - - static final String NAME = "HelloInjectionApplication"; - - public HelloInjection$$Application() { - assert(true); // for setting breakpoints in debug - } - - @Override - public Optional named() { - return Optional.of(NAME); - } - - @Override - public void configure(ServiceInjectionPlanBinder binder) { - if (!ENABLED) { - return; - } - - binder.bindTo(HelloInjectionImpl$$injectionActivator.INSTANCE) - .bind(HelloInjectionWorld.class.getPackageName() + ".world", InjectionWorldImpl$$injectionActivator.INSTANCE) - .bind(HelloInjectionWorld.class.getPackageName() + ".worldRef", InjectionWorldImpl$$injectionActivator.INSTANCE) - .bindMany(HelloInjectionWorld.class.getPackageName() + ".listOfWorldRefs", InjectionWorldImpl$$injectionActivator.INSTANCE) - .bindMany(HelloInjectionWorld.class.getPackageName() + ".listOfWorlds", InjectionWorldImpl$$injectionActivator.INSTANCE) - .bindVoid(HelloInjectionWorld.class.getPackageName() + ".redWorld") - .bind(HelloInjectionWorld.class.getPackageName() + ".world|1(1)", InjectionWorldImpl$$injectionActivator.INSTANCE) - .commit(); - - binder.bindTo(InjectionWorldImpl$$injectionActivator.INSTANCE) - .commit(); - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjection$$Module.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjection$$Module.java deleted file mode 100644 index 1f4f468f90b..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjection$$Module.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import java.util.Optional; - -import io.helidon.common.Generated; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceBinder; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -@Generated(value = "example", comments = "API Version: n", trigger = "io.helidon.inject.tools.ActivatorCreatorDefault") -@Singleton -@Named(HelloInjection$$Module.NAME) -public final class HelloInjection$$Module implements ModuleComponent { - - public static final String NAME = "example"; - - public HelloInjection$$Module() { - } - - @Override - public Optional named() { - return Optional.of(NAME); - } - - @Override - public void configure(ServiceBinder binder) { - binder.bind(HelloInjectionImpl$$injectionActivator.INSTANCE); - binder.bind(InjectionWorldImpl$$injectionActivator.INSTANCE); - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionImpl$$injectionActivator.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionImpl$$injectionActivator.java deleted file mode 100644 index a143f46fdfe..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionImpl$$injectionActivator.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.Generated; -import io.helidon.common.Weight; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.PostConstructMethod; -import io.helidon.inject.api.PreDestroyMethod; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.runtime.AbstractServiceProvider; -import io.helidon.inject.runtime.Dependencies; - -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -import static io.helidon.inject.api.ServiceInfoBasics.DEFAULT_INJECT_WEIGHT; - -/** - * Serves as an exemplar of what will is normally code generated. - */ -@Generated(value = "example", comments = "API Version: N", trigger = "io.helidon.inject.runtime.testsubjects.HelloInjectionImpl") -@Singleton -@Weight(DEFAULT_INJECT_WEIGHT) -@SuppressWarnings({"unchecked", "checkstyle:TypeName"}) -public class HelloInjectionImpl$$injectionActivator extends AbstractServiceProvider { - - private static final ServiceInfo serviceInfo = - ServiceInfo.builder() - .serviceTypeName(HelloInjectionWorldImpl.class) - .activatorTypeName(HelloInjectionImpl$$injectionActivator.class) - .addContractImplemented(HelloInjectionWorld.class) - .addScopeTypeName(Singleton.class) - .declaredRunLevel(0) - .build(); - - public static final HelloInjectionImpl$$injectionActivator INSTANCE = new HelloInjectionImpl$$injectionActivator(); - - public HelloInjectionImpl$$injectionActivator() { - serviceInfo(serviceInfo); - } - - @Override - public Class serviceType() { - return HelloInjectionWorldImpl.class; - } - - @Override - public DependenciesInfo dependencies() { - DependenciesInfo deps = Dependencies.builder(HelloInjectionWorldImpl.class) - .add("world", InjectionWorld.class, ElementKind.FIELD, AccessModifier.PACKAGE_PRIVATE).ipName("world").ipType(TypeName.create( - InjectionWorld.class)) - .add("worldRef", InjectionWorld.class, ElementKind.FIELD, AccessModifier.PACKAGE_PRIVATE) - .providerWrapped().ipName("worldRef").ipType(TypeName.create(Provider.class)) - .add("listOfWorlds", InjectionWorld.class, ElementKind.FIELD, AccessModifier.PACKAGE_PRIVATE) - .listWrapped().ipName("listOfWorlds").ipType(TypeName.create(List.class)) - .add("listOfWorldRefs", InjectionWorld.class, ElementKind.FIELD, AccessModifier.PACKAGE_PRIVATE) - .listWrapped().providerWrapped().ipName("listOfWorldRefs").ipType(TypeName.create(List.class)) - .add("redWorld", InjectionWorld.class, ElementKind.FIELD, AccessModifier.PACKAGE_PRIVATE) - .named("red").optionalWrapped().ipName("redWorld").ipType(TypeName.create(Optional.class)) - .add("world", InjectionWorld.class, ElementKind.METHOD, 1, AccessModifier.PACKAGE_PRIVATE) - .elemOffset(1).ipName("world").ipType(TypeName.create(InjectionWorld.class)) - .build(); - return Dependencies.combine(super.dependencies(), deps); - } - - @Override - protected HelloInjectionWorldImpl createServiceProvider(Map deps) { - return new HelloInjectionWorldImpl(); - } - - @Override - protected void doInjectingFields(Object t, Map deps, Set injections, TypeName forServiceType) { - super.doInjectingFields(t, deps, injections, forServiceType); - HelloInjectionWorldImpl target = (HelloInjectionWorldImpl) t; - target.world = Objects.requireNonNull( - (InjectionWorld) deps.get(InjectionWorld.class.getPackageName() + ".world"), "world"); - target.worldRef = Objects.requireNonNull( - (Provider) deps.get(InjectionWorld.class.getPackageName() + ".worldRef"), "worldRef"); - target.listOfWorldRefs = Objects.requireNonNull( - (List>) deps.get(InjectionWorld.class.getPackageName() + ".listOfWorldRefs"), "listOfWorldRefs"); - target.listOfWorlds = Objects.requireNonNull( - (List) deps.get(InjectionWorld.class.getPackageName() + ".listOfWorlds"), "listOfWorlds"); - target.redWorld = Objects.requireNonNull( - (Optional) deps.get(InjectionWorld.class.getPackageName() + ".redWorld"), "redWorld"); - } - - @Override - protected void doInjectingMethods(Object t, Map deps, Set injections, TypeName forServiceType) { - super.doInjectingMethods(t, deps, injections, forServiceType); - HelloInjectionWorldImpl target = (HelloInjectionWorldImpl)t; - target.world(Objects.requireNonNull( - (InjectionWorld) deps.get(InjectionWorld.class.getPackageName() + ".world|1(1)"))); - } - - @Override - public Optional postConstructMethod() { - HelloInjectionWorldImpl impl = serviceRef().get(); - return Optional.of(impl::postConstruct); - } - - @Override - public Optional preDestroyMethod() { - HelloInjectionWorldImpl impl = serviceRef().get(); - return Optional.of(impl::preDestroy); - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionWorld.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionWorld.java deleted file mode 100644 index 3758843f37c..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionWorld.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import io.helidon.inject.api.Contract; - -/** - * For testing. - */ -@Contract -public interface HelloInjectionWorld { - - /** - * For testing. - * - * @return for testing - */ - String sayHello(); - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionWorldImpl.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionWorldImpl.java deleted file mode 100644 index e26335bb9a1..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/HelloInjectionWorldImpl.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import java.util.List; -import java.util.Optional; - -import io.helidon.inject.api.RunLevel; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@SuppressWarnings("OptionalUsedAsFieldOrParameterType") -@Singleton -@RunLevel(0) -public class HelloInjectionWorldImpl implements HelloInjectionWorld { - - @Inject - InjectionWorld world; - - @Inject - Provider worldRef; - - @Inject - List> listOfWorldRefs; - - @Inject - List listOfWorlds; - - @Inject @Named("red") - Optional redWorld; - - private InjectionWorld setWorld; - - int postConstructCallCount; - int preDestroyCallCount; - - @Override - public String sayHello() { - assert(postConstructCallCount == 1); - assert(preDestroyCallCount == 0); - assert(world == worldRef.get()); - assert(world == setWorld); - assert(redWorld.isEmpty()); - - return "Hello " + world.name(); - } - - @Inject - void world(InjectionWorld world) { - this.setWorld = world; - } - - @PostConstruct - public void postConstruct() { - postConstructCallCount++; - } - - @PreDestroy - public void preDestroy() { - preDestroyCallCount++; - } - - public int postConstructCallCount() { - return postConstructCallCount; - } - - public int preDestroyCallCount() { - return preDestroyCallCount; - } - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorld.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorld.java deleted file mode 100644 index 89680d45075..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorld.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -/** - * For testing. - */ -// @Contract - we will test ExternalContracts here instead -public interface InjectionWorld { - - /** - * For testing. - * - * @return for testing - */ - String name(); - -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorldImpl$$injectionActivator.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorldImpl$$injectionActivator.java deleted file mode 100644 index de53e8a6fb2..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorldImpl$$injectionActivator.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import java.util.Map; - -import io.helidon.common.Generated; -import io.helidon.common.Weight; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.runtime.AbstractServiceProvider; -import io.helidon.inject.runtime.Dependencies; - -import jakarta.inject.Singleton; - -import static io.helidon.inject.api.ServiceInfoBasics.DEFAULT_INJECT_WEIGHT; - -@Generated(value = "example", comments = "API Version: n", trigger = "io.helidon.inject.runtime.testsubjects.InjectionWorldImpl") -@Singleton -@Weight(DEFAULT_INJECT_WEIGHT) -public class InjectionWorldImpl$$injectionActivator extends AbstractServiceProvider { - private static final ServiceInfo serviceInfo = - ServiceInfo.builder() - .serviceTypeName(InjectionWorldImpl.class) - .activatorTypeName(InjectionWorldImpl$$injectionActivator.class) - .addExternalContractImplemented(InjectionWorld.class) - .addScopeTypeName(Singleton.class) - .declaredWeight(DEFAULT_INJECT_WEIGHT) - .build(); - - public static final InjectionWorldImpl$$injectionActivator INSTANCE = new InjectionWorldImpl$$injectionActivator(); - - InjectionWorldImpl$$injectionActivator() { - serviceInfo(serviceInfo); - } - - @Override - public DependenciesInfo dependencies() { - DependenciesInfo dependencies = Dependencies.builder(InjectionWorldImpl.class) - .build(); - return Dependencies.combine(super.dependencies(), dependencies); - } - - @Override - protected InjectionWorldImpl createServiceProvider(Map deps) { - return new InjectionWorldImpl(); - } - - @Override - public Class serviceType() { - return InjectionWorldImpl.class; - } -} diff --git a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorldImpl.java b/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorldImpl.java deleted file mode 100644 index ae1b5f85365..00000000000 --- a/inject/tests/runtime/src/test/java/io/helidon/inject/runtime/testsubjects/InjectionWorldImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.runtime.testsubjects; - -import io.helidon.inject.api.ExternalContracts; - -@ExternalContracts(InjectionWorld.class) -public class InjectionWorldImpl implements InjectionWorld { - private final String name; - - InjectionWorldImpl() { - this("inject"); - } - - InjectionWorldImpl(String name) { - this.name = name; - } - - @Override - public String name() { - return name; - } - -} diff --git a/inject/tests/runtime/src/test/resources/META-INF/services/io.helidon.inject.api.Application b/inject/tests/runtime/src/test/resources/META-INF/services/io.helidon.inject.api.Application deleted file mode 100644 index 2fc304751dd..00000000000 --- a/inject/tests/runtime/src/test/resources/META-INF/services/io.helidon.inject.api.Application +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -io.helidon.inject.runtime.testsubjects.HelloInjection$$Application diff --git a/inject/tests/runtime/src/test/resources/META-INF/services/io.helidon.inject.api.ModuleComponent b/inject/tests/runtime/src/test/resources/META-INF/services/io.helidon.inject.api.ModuleComponent deleted file mode 100644 index dd99203a03b..00000000000 --- a/inject/tests/runtime/src/test/resources/META-INF/services/io.helidon.inject.api.ModuleComponent +++ /dev/null @@ -1,18 +0,0 @@ -# -# Copyright (c) 2023 Oracle and/or its affiliates. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -io.helidon.inject.runtime.testsubjects.HelloInjection$$Module -io.helidon.inject.runtime.testsubjects.EmptyModule diff --git a/inject/tests/tck-jsr330/pom.xml b/inject/tests/tck-jsr330/pom.xml deleted file mode 100644 index e225ad73f0d..00000000000 --- a/inject/tests/tck-jsr330/pom.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - io.helidon.inject.tests - helidon-inject-tests-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-tests-tck-jsr330 - Helidon Injection Test JSR-330 TCK - - - true - true - - - - - jakarta.inject - jakarta.inject-tck - - - junit - junit - - - - - io.helidon.inject - helidon-inject-runtime - - - io.helidon.inject - helidon-inject-maven-plugin - ${helidon.version} - provided - true - - - jakarta.inject - jakarta.inject-api - provided - - - jakarta.annotation - jakarta.annotation-api - provided - - - io.helidon.inject - helidon-inject-testing - test - - - junit - junit - ${version.lib.junit4} - - - org.hamcrest - hamcrest-all - test - - - - - - - io.helidon.inject - helidon-inject-maven-plugin - ${helidon.version} - - - - external-module-create - - - - - - -Ainject.debug=${inject.debug} - -Ainject.autoAddNonContractInterfaces=true - - - org.atinject.tck.auto - org.atinject.tck.auto.accessories - - true - - - org.atinject.tck.auto.accessories.SpareTire - - - jakarta.inject.Named - spare - - - - - org.atinject.tck.auto.DriversSeat - - - org.atinject.tck.auto.Drivers - - - - - - - - - - diff --git a/inject/tests/tck-jsr330/src/test/java/io/helidon/inject/tests/tck/jsr330/Jsr330TckTest.java b/inject/tests/tck-jsr330/src/test/java/io/helidon/inject/tests/tck/jsr330/Jsr330TckTest.java deleted file mode 100644 index 3b5d5fca877..00000000000 --- a/inject/tests/tck-jsr330/src/test/java/io/helidon/inject/tests/tck/jsr330/Jsr330TckTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tests.tck.jsr330; - -import java.util.Enumeration; -import java.util.Objects; - -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesConfig; - -import jakarta.inject.Provider; -import junit.framework.TestFailure; -import junit.framework.TestResult; -import org.atinject.tck.Tck; -import org.atinject.tck.auto.Car; -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; - -/** - * Jsr-330 TCK Testing. - * This test requires the annotation processing and the maven-plugin to run - see pom.xml. - */ -class Jsr330TckTest { - - /** - * Run's the TCK tests. - */ - @Test - void testItAll() { - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - InjectionServicesConfig cfg = injectionServices.config(); - Provider carProvider = injectionServices.services().lookupFirst(Car.class); - Objects.requireNonNull(carProvider.get()); - assertThat("sanity", carProvider.get(), not(carProvider.get())); - junit.framework.Test jsrTest = Tck.testsFor(carProvider.get(), - cfg.supportsJsr330Statics(), - cfg.supportsJsr330Privates()); - TestResult result = new TestResult(); - jsrTest.run(result); - assertThat(result.runCount(), greaterThan(0)); - assertThat(toFailureReport(result), result.wasSuccessful(), is(true)); - } - - String toFailureReport(TestResult result) { - StringBuilder builder = new StringBuilder(); - int count = 0; - Enumeration failures = result.failures(); - while (failures.hasMoreElements()) { - TestFailure failure = failures.nextElement(); - builder.append("\nFAILURE #").append(++count).append(" : ") - .append(failure.trace()) - .append("\n"); - } - return builder.toString(); - } - -} diff --git a/inject/tools/README.md b/inject/tools/README.md deleted file mode 100644 index cfbb904885d..00000000000 --- a/inject/tools/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# inject-tools - -This module is primarily used at compile-time only. diff --git a/inject/tools/etc/spotbugs/exclude.xml b/inject/tools/etc/spotbugs/exclude.xml deleted file mode 100644 index 29e45a5638f..00000000000 --- a/inject/tools/etc/spotbugs/exclude.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/inject/tools/pom.xml b/inject/tools/pom.xml deleted file mode 100644 index 8af1afed437..00000000000 --- a/inject/tools/pom.xml +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - io.helidon.inject - helidon-inject-project - 4.2.0-SNAPSHOT - - 4.0.0 - - helidon-inject-tools - Helidon Injection Tools - - - etc/spotbugs/exclude.xml - - - - - io.helidon.common - helidon-common-types - - - io.helidon.inject - helidon-inject-api - - - io.helidon.inject - helidon-inject-runtime - - - io.helidon.common - helidon-common - - - io.helidon.config - helidon-config-metadata - provided - - - io.helidon.common - helidon-common-config - - - com.github.jknack - handlebars - - - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-jdk14 - - - io.github.classgraph - classgraph - - - io.helidon.builder - helidon-builder-api - - - io.helidon.common.processor - helidon-common-processor - - - jakarta.inject - jakarta.inject-api - compile - - - jakarta.annotation - jakarta.annotation-api - provided - - - org.hamcrest - hamcrest-all - test - - - org.junit.jupiter - junit-jupiter-api - test - - - io.helidon.common.testing - helidon-common-testing-junit5 - test - - - jakarta.inject - jakarta.inject-tck - test - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - - - - io.helidon.builder - helidon-builder-processor - ${helidon.version} - - - - - - diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/AbstractCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/AbstractCreator.java deleted file mode 100644 index 825042b7f7a..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/AbstractCreator.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.runtime.AbstractServiceProvider; -import io.helidon.inject.runtime.ServiceBinderDefault; - -import static io.helidon.inject.tools.TypeTools.needToDeclareModuleUsage; -import static io.helidon.inject.tools.TypeTools.needToDeclarePackageUsage; - -/** - * Abstract base for any codegen creator. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public abstract class AbstractCreator { - /** - * The default java source version (this can be explicitly overridden using the builder or maven plugin). - */ - public static final String DEFAULT_SOURCE = "11"; - /** - * The default java target version (this can be explicitly overridden using the builder or maven plugin). - */ - public static final String DEFAULT_TARGET = "11"; - - // no special chars since this will be used as a package and class name - static final String NAME_PREFIX = "Injection$$"; - static final String INJECT_FRAMEWORK_MODULE = "io.helidon.inject.runtime"; - static final String MODULE_NAME_SUFFIX = "Module"; - - private final System.Logger logger = System.getLogger(getClass().getName()); - private final TemplateHelper templateHelper; - private final String templateName; - - AbstractCreator(String templateName) { - this.templateHelper = TemplateHelper.create(); - this.templateName = templateName; - } - - /** - * Generates the {@link Activator} source code for the provided service providers. Custom - * service providers (see {@link AbstractServiceProvider#isCustom()}) do not qualify to - * have activators code generated. - * - * @param sp the collection of service providers - * @return the code generated string for the service provider given - */ - static String toActivatorCodeGen(ServiceProvider sp) { - if (sp instanceof AbstractServiceProvider && ((AbstractServiceProvider) sp).isCustom()) { - return null; - } - return ServiceBinderDefault.toRootProvider(sp).activator().orElseThrow().getClass().getName() + ".INSTANCE"; - } - - /** - * Generates the {@link Activator} source code for the provided service providers. - * - * @param coll the collection of service providers - * @return the code generated string for the collection of service providers given - */ - static String toActivatorCodeGen(Collection> coll) { - return CommonUtils.toString(coll, AbstractCreator::toActivatorCodeGen, null); - } - - static Set toAllContracts(Map> servicesToContracts) { - Set result = new LinkedHashSet<>(); - servicesToContracts.forEach((serviceTypeName, cn) -> result.addAll(cn)); - return result; - } - - /** - * Creates the {@link CodeGenPaths} given the current batch of services to process. - * - * @param servicesToProcess the services to process - * @return the payload for code gen paths - */ - static CodeGenPaths createCodeGenPaths(ServicesToProcess servicesToProcess) { - Path moduleInfoFilePath = servicesToProcess.lastGeneratedModuleInfoFilePath(); - if (moduleInfoFilePath == null) { - moduleInfoFilePath = servicesToProcess.lastKnownModuleInfoFilePath(); - } - return CodeGenPaths.builder() - .moduleInfoPath(Optional.ofNullable((moduleInfoFilePath != null) ? moduleInfoFilePath.toString() : null)) - .build(); - } - - System.Logger logger() { - return logger; - } - - TemplateHelper templateHelper() { - return templateHelper; - } - - String templateName() { - return templateName; - } - - /** - * Creates a codegen filer that is not reliant on annotation processing, but still capable of creating source - * files and resources. - * - * @param paths the paths for where files should be read or written. - * @param isAnalysisOnly true if analysis only, where no code or resources will be physically written to disk - * @return the code gen filer instance to use - */ - CodeGenFiler createDirectCodeGenFiler(CodeGenPaths paths, - boolean isAnalysisOnly) { - AbstractFilerMessager filer = AbstractFilerMessager.createDirectFiler(paths, logger); - return new CodeGenFiler(filer, !isAnalysisOnly); - } - - /** - * The generated sticker string. - * - * @param generator type of the generator (annotation processor) - * @param trigger type of the trigger (class that caused the annotation processing, or annotation processor itself) - * @param generatedType type of the generated class - * @return the sticker - */ - String toGeneratedSticker(TypeName generator, TypeName trigger, TypeName generatedType) { - return templateHelper.generatedStickerFor(generator, - trigger, - generatedType); - } - - /** - * Automatically adds the requirements to the module-info descriptor for what Injection requires. - * - * @param moduleInfo the module info descriptor - * @param generatedAnno the generator sticker value - * @return the modified descriptor, fluent style - */ - ModuleInfoDescriptor.Builder addProviderRequirementsTo(ModuleInfoDescriptor.Builder moduleInfo, - String generatedAnno) { - Objects.requireNonNull(generatedAnno); - // requirements on the injection services framework itself - String preComment = " // Injection Runtime - " + generatedAnno; - ModuleInfoUtil.addIfAbsent(moduleInfo, INJECT_FRAMEWORK_MODULE, ModuleInfoItem.builder() - .requires(true) - .target(INJECT_FRAMEWORK_MODULE) - .isTransitiveUsed(true) - .addPrecomment(preComment)); - return moduleInfo; - } - - ModuleInfoDescriptor createModuleInfo(ModuleInfoCreatorRequest req) { - TypeName processor = TypeName.create(getClass()); - - String generatedAnno = templateHelper.generatedStickerFor(processor, processor, TypeName.create("module-info")); - String moduleInfoPath = req.moduleInfoPath().orElse(null); - String moduleName = req.name().orElse(null); - TypeName moduleTypeName = req.moduleTypeName(); - TypeName applicationTypeName = req.applicationTypeName().orElse(null); - String classPrefixName = req.classPrefixName(); - boolean isModuleCreated = req.moduleCreated(); - boolean isApplicationCreated = req.applicationCreated(); - Collection modulesRequired = req.modulesRequired(); - Map> contracts = req.contracts(); - Map> externalContracts = req.externalContracts(); - - ModuleInfoDescriptor.Builder descriptorBuilder; - if (moduleInfoPath != null) { - descriptorBuilder = ModuleInfoDescriptor - .builder(ModuleInfoDescriptor.create(Paths.get(moduleInfoPath))); - if (CommonUtils.hasValue(moduleName) && ModuleUtils.isUnnamedModuleName(descriptorBuilder.name())) { - descriptorBuilder.name(moduleName); - } - assert (descriptorBuilder.name().equals(moduleName) || (!CommonUtils.hasValue(moduleName))) - : "bad module name: " + moduleName + " targeting " + descriptorBuilder.name(); - moduleName = descriptorBuilder.name(); - } else { - descriptorBuilder = ModuleInfoDescriptor.builder().name(moduleName); - descriptorBuilder.headerComment("// " + generatedAnno); - } - - boolean isTestModule = "test".equals(classPrefixName); - if (isTestModule) { - String baseModuleName = ModuleUtils.normalizedBaseModuleName(moduleName); - ModuleInfoUtil.addIfAbsent(descriptorBuilder, baseModuleName, ModuleInfoItem.builder() - .requires(true) - .target(baseModuleName) - .isTransitiveUsed(true)); - } - - if (isModuleCreated && (moduleTypeName != null)) { - if (!isTestModule) { - ModuleInfoUtil.addIfAbsent(descriptorBuilder, moduleTypeName.packageName(), - ModuleInfoItem.builder() - .exports(true) - .target(moduleTypeName.packageName())); - } - ModuleInfoUtil.addIfAbsent(descriptorBuilder, TypeNames.INJECT_MODULE, - ModuleInfoItem.builder() - .provides(true) - .target(TypeNames.INJECT_MODULE) - .addWithOrTo(moduleTypeName.name()) - .addPrecomment(" // Module Component - " + generatedAnno)); - } - if (isApplicationCreated && applicationTypeName != null) { - if (!isTestModule) { - ModuleInfoUtil.addIfAbsent(descriptorBuilder, applicationTypeName.packageName(), - ModuleInfoItem.builder() - .exports(true) - .target(applicationTypeName.packageName())); - } - ModuleInfoUtil.addIfAbsent(descriptorBuilder, TypeNames.INJECT_APPLICATION, - ModuleInfoItem.builder() - .provides(true) - .target(TypeNames.INJECT_APPLICATION) - .addWithOrTo(applicationTypeName.name()) - .addPrecomment(" // Application - " + generatedAnno)); - } - - String preComment = " // External contract usage - " + generatedAnno; - if (modulesRequired != null) { - for (String externalModuleName : modulesRequired) { - if (!needToDeclareModuleUsage(externalModuleName)) { - continue; - } - - ModuleInfoItem.Builder itemBuilder = ModuleInfoItem.builder() - .requires(true) - .target(externalModuleName); - if (CommonUtils.hasValue(preComment)) { - itemBuilder.addPrecomment(preComment); - } - - boolean added = ModuleInfoUtil.addIfAbsent(descriptorBuilder, externalModuleName, itemBuilder); - if (added) { - preComment = ""; - } - } - } - - Set allExternalContracts = toAllContracts(externalContracts); - if (!isTestModule && (contracts != null)) { - preComment = " // Contract usage - " + generatedAnno; - for (Map.Entry> e : contracts.entrySet()) { - for (TypeName contract : e.getValue()) { - if (!allExternalContracts.contains(contract)) { - String packageName = contract.packageName(); - if (!needToDeclarePackageUsage(packageName)) { - continue; - } - - ModuleInfoItem.Builder itemBuilder = ModuleInfoItem.builder() - .exports(true) - .target(packageName); - if (CommonUtils.hasValue(preComment)) { - itemBuilder.addPrecomment(preComment); - } - - boolean added = ModuleInfoUtil.addIfAbsent(descriptorBuilder, packageName, itemBuilder); - if (added) { - preComment = ""; - } - } - } - } - } - - return addProviderRequirementsTo(descriptorBuilder, generatedAnno) - .build(); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/AbstractFilerMessager.java b/inject/tools/src/main/java/io/helidon/inject/tools/AbstractFilerMessager.java deleted file mode 100644 index 29ba7e35a8e..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/AbstractFilerMessager.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Objects; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.NestingKind; -import javax.tools.FileObject; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; - -import io.helidon.common.types.TypeName; - -/** - * Used to abstract processor based filer from direct filer (the latter used via maven plugin and other tooling). - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public abstract class AbstractFilerMessager implements Filer, Messager { - private static final System.Logger LOGGER = System.getLogger(AbstractFilerMessager.class.getName()); - - private final Filer filerDelegate; - private final Messager msgrDelegate; - private final System.Logger logger; - - AbstractFilerMessager(Filer filerDelegate, - Messager msgr) { - this.filerDelegate = filerDelegate; - this.msgrDelegate = msgr; - this.logger = LOGGER; - } - - AbstractFilerMessager(System.Logger logger) { - this.filerDelegate = null; - this.msgrDelegate = null; - this.logger = logger; - } - - /** - * Create an annotation based filer abstraction. - * - * @param processingEnv the processing env - * @param msgr the messager and error handler - * @return the filer facade - */ - public static AbstractFilerMessager createAnnotationBasedFiler(ProcessingEnvironment processingEnv, - Messager msgr) { - return new AbstractFilerMessager(Objects.requireNonNull(processingEnv.getFiler()), msgr) { }; - } - - /** - * Create a direct filer, not from annotation processing. - * - * @param paths the code paths - * @param logger the logger for messaging - * @return the filer facade - */ - public static AbstractFilerMessager createDirectFiler(CodeGenPaths paths, - System.Logger logger) { - return new DirectFilerMessager(Objects.requireNonNull(paths), logger) { }; - } - - System.Logger logger() { - return logger; - } - - @Override - public JavaFileObject createSourceFile(CharSequence name, - Element... originatingElements) throws IOException { - if (filerDelegate != null) { - return filerDelegate.createSourceFile(name, originatingElements); - } - throw new IllegalStateException(); - } - - @Override - public JavaFileObject createClassFile(CharSequence name, - Element... originatingElements) throws IOException { - if (filerDelegate != null) { - return filerDelegate.createClassFile(name, originatingElements); - } - throw new IllegalStateException(); - } - - @Override - public FileObject createResource(JavaFileManager.Location location, - CharSequence moduleAndPkg, - CharSequence relativeName, - Element... originatingElements) throws IOException { - if (filerDelegate != null) { - return filerDelegate.createResource(location, moduleAndPkg, relativeName, originatingElements); - } - throw new IllegalStateException(); - } - - @Override - public FileObject getResource(JavaFileManager.Location location, - CharSequence moduleAndPkg, - CharSequence relativeName) throws IOException { - if (filerDelegate != null) { - return filerDelegate.getResource(location, moduleAndPkg, relativeName); - } - throw new IllegalStateException(); - } - - @Override - public void debug(String message) { - if (msgrDelegate != null) { - msgrDelegate.debug(message); - } - if (logger != null) { - logger.log(System.Logger.Level.DEBUG, message); - } - } - - @Override - public void debug(String message, - Throwable t) { - if (msgrDelegate != null) { - msgrDelegate.debug(message, t); - } - if (logger != null) { - logger.log(System.Logger.Level.DEBUG, message, t); - } - } - - @Override - public void log(String message) { - if (msgrDelegate != null) { - msgrDelegate.log(message); - } - if (logger != null) { - logger.log(System.Logger.Level.INFO, message); - } - } - - @Override - public void warn(String message) { - if (msgrDelegate != null) { - msgrDelegate.warn(message); - } - if (logger != null) { - logger.log(System.Logger.Level.WARNING, message); - } - } - - @Override - public void warn(String message, - Throwable t) { - if (msgrDelegate != null) { - msgrDelegate.warn(message, t); - } - if (logger != null) { - logger.log(System.Logger.Level.WARNING, message, t); - } - } - - @Override - public void error(String message, - Throwable t) { - if (msgrDelegate != null) { - msgrDelegate.warn(message, t); - } - if (logger != null) { - logger.log(System.Logger.Level.ERROR, message, t); - } - } - - static class DirectFilerMessager extends AbstractFilerMessager { - private final CodeGenPaths paths; - - DirectFilerMessager(CodeGenPaths paths, - System.Logger logger) { - super(logger); - this.paths = paths; - } - - CodeGenPaths codeGenPaths() { - return paths; - } - - @Override - public FileObject getResource(JavaFileManager.Location location, - CharSequence moduleAndPkg, - CharSequence relativeName) throws IOException { - return getResource(location, moduleAndPkg, relativeName, false); - } - - @Override - public FileObject createResource(JavaFileManager.Location location, - CharSequence moduleAndPkg, - CharSequence relativeName, - Element... originatingElements) throws IOException { - return getResource(location, moduleAndPkg, relativeName, false); - } - - @Override - public JavaFileObject createSourceFile(CharSequence name, - Element... originatingElement) { - Path javaFilePath = Objects.requireNonNull(toSourcePath(StandardLocation.SOURCE_OUTPUT, name.toString())); - return new DirectJavaFileObject(javaFilePath.toFile()); - } - - Path toSourcePath(JavaFileManager.Location location, - String name) { - return toSourcePath(location, TypeName.create(name)); - } - - Path toSourcePath(JavaFileManager.Location location, - TypeName typeName) { - String sourcePath; - if (StandardLocation.SOURCE_PATH == location) { - sourcePath = paths.sourcePath().orElse(null); - } else if (StandardLocation.SOURCE_OUTPUT == location) { - sourcePath = paths.generatedSourcesPath().orElse(null); - } else { - throw new ToolsException("Unable to determine location of " + typeName + " with " + location); - } - - if (sourcePath == null) { - LOGGER.log(System.Logger.Level.DEBUG, "sourcepath is not defined in " + paths); - return null; - } - - return new File(sourcePath, TypeTools.toFilePath(typeName)).toPath(); - } - - private FileObject getResource(JavaFileManager.Location location, - CharSequence ignoreModuleAndPkg, - CharSequence relativeName, - boolean expectedToExist) throws IOException { - if (StandardLocation.CLASS_OUTPUT != location) { - throw new IllegalStateException(location + " is not supported for: " + relativeName); - } - - File outDir = new File(paths.outputPath().orElseThrow()); - File resourceFile = new File(outDir, relativeName.toString()); - if (expectedToExist && !resourceFile.exists()) { - throw new NoSuchFileException(resourceFile.getPath()); - } - - return new DirectFileObject(resourceFile); - } - } - - static class DirectFileObject implements FileObject { - private final File file; - - DirectFileObject(File file) { - this.file = file; - } - - @Override - public URI toUri() { - return file.toURI(); - } - - @Override - public String getName() { - return file.getName(); - } - - @Override - public InputStream openInputStream() throws IOException { - return new FileInputStream(file); - } - - @Override - public OutputStream openOutputStream() throws IOException { - Path parent = Paths.get(file.getParent()); - Files.createDirectories(parent); - return new FileOutputStream(file); - } - - @Override - public Reader openReader(boolean ignoreEncodingErrors) throws IOException { - return new InputStreamReader(openInputStream(), StandardCharsets.UTF_8); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return Files.readString(file.toPath(), StandardCharsets.UTF_8); - } - - @Override - public Writer openWriter() throws IOException { - return new OutputStreamWriter(openOutputStream(), StandardCharsets.UTF_8); - } - - @Override - public long getLastModified() { - return file.lastModified(); - } - - @Override - public boolean delete() { - return file.delete(); - } - - @Override - public String toString() { - return String.valueOf(file); - } - } - - static class DirectJavaFileObject extends DirectFileObject implements JavaFileObject { - DirectJavaFileObject(File javaFile) { - super(javaFile); - } - - @Override - public JavaFileObject.Kind getKind() { - return JavaFileObject.Kind.SOURCE; - } - - @Override - public boolean isNameCompatible(String simpleName, - JavaFileObject.Kind kind) { - throw new IllegalStateException(); - } - - @Override - public NestingKind getNestingKind() { - throw new IllegalStateException(); - } - - @Override - public Modifier getAccessLevel() { - throw new IllegalStateException(); - } - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCodeGenDetailBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCodeGenDetailBlueprint.java deleted file mode 100644 index ca834d187fc..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCodeGenDetailBlueprint.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ServiceInfoBasics; - -/** - * The specifics for a single {@link io.helidon.inject.api.ServiceProvider} that was code generated. - * - * @see ActivatorCreatorResponse#serviceTypeDetails() - */ -@Prototype.Blueprint -interface ActivatorCodeGenDetailBlueprint extends GeneralCodeGenDetailBlueprint { - - /** - * The additional meta-information describing what is offered by the generated service. - * - * @return additional meta-information describing the generated service info - */ - ServiceInfoBasics serviceInfo(); - - /** - * The additional meta-information describing what the generated service depends upon. - * - * @return additional meta-information describing what the generated service depends upon - */ - Optional dependencies(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorArgsBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorArgsBlueprint.java deleted file mode 100644 index 07a8a485562..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorArgsBlueprint.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ServiceInfoBasics; - -/** - * See {@link ActivatorCreatorDefault}. - */ -@Prototype.Blueprint(isPublic = false) -interface ActivatorCreatorArgsBlueprint { - String constructor(); - String template(); - TypeName serviceTypeName(); - TypeName activatorTypeName(); - Optional activatorGenericDecl(); - Optional parentTypeName(); - Set scopeTypeNames(); - List description(); - ServiceInfoBasics serviceInfo(); - Optional dependencies(); - Optional parentDependencies(); - Collection injectionPointsSkippedInParent(); - List serviceTypeInjectionOrder(); - String generatedSticker(); - Optional weightedPriority(); - Optional runLevel(); - Optional postConstructMethodName(); - Optional preDestroyMethodName(); - List extraCodeGen(); - List extraClassComments(); - boolean isConcrete(); - boolean isProvider(); - boolean isSupportsJsr330InStrictMode(); -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorCodeGenBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorCodeGenBlueprint.java deleted file mode 100644 index 6976a2dcf77..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorCodeGenBlueprint.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.Qualifier; - -/** - * Codegen request options applicable as part of the overall {@link ActivatorCreatorRequest}. - * - * @see ActivatorCreatorRequest - */ -@Prototype.Blueprint -interface ActivatorCreatorCodeGenBlueprint { - - /** - * The default prefix for {@link #classPrefixName()}. - */ - String DEFAULT_CLASS_PREFIX_NAME = ""; - - /** - * Optionally, for each service type also provide its parent (super class) service type mapping. - * - * @return the service type to parent (super class) service type mapping - */ - Map serviceTypeToParentServiceTypes(); - - /** - * The class hierarchy from Object down to and including this service type. - * - * @return the map of service type names to its class hierarchy - */ - Map> serviceTypeHierarchy(); - - /** - * Optionally, for each service, provide the generic declaration portion for the activator generic class name. - * - * @return the generic declaration portion for the activator generic class name - */ - Map serviceTypeToActivatorGenericDecl(); - - /** - * The map of service type names to access level. - * - * @return the map of service type names to each respective access level - */ - Map serviceTypeAccessLevels(); - - /** - * The map of service type names to whether they are abstract. If not found then assume concrete. - * - * @return the map of service type names to whether they are abstract - */ - Map serviceTypeIsAbstractTypes(); - - /** - * The {@link io.helidon.inject.api.Contract}'s associated with each service type. - * - * @return the map of service type names to {@link io.helidon.inject.api.Contract}'s implemented - */ - Map> serviceTypeContracts(); - - /** - * The {@link io.helidon.inject.api.ExternalContracts} associated with each service type. - * - * @return the map of service type names to {@link io.helidon.inject.api.ExternalContracts} implemented - */ - Map> serviceTypeExternalContracts(); - - /** - * The injection point dependencies for each service type. - * - * @return the map of service type names to injection point dependencies info - */ - Map serviceTypeInjectionPointDependencies(); - - /** - * Default constructor override for each service type. - * - * @return map of service types to custom constructor code - */ - Map serviceTypeDefaultConstructors(); - - /** - * The {@code PreDestroy} method name for each service type. - * - * @return the map of service type names to PreDestroy method names - * @see io.helidon.inject.api.PreDestroyMethod - */ - Map serviceTypePreDestroyMethodNames(); - - /** - * The {@code PostConstruct} method name for each service type. - * - * @return the map of service type names to PostConstruct method names - * @see io.helidon.inject.api.PostConstructMethod - */ - Map serviceTypePostConstructMethodNames(); - - /** - * The declared {@link io.helidon.common.Weighted} value for each service type. - * - * @return the map of service type names to declared weight - */ - Map serviceTypeWeights(); - - /** - * The declared {@link io.helidon.inject.api.RunLevel} value for each service type. - * - * @return the map of service type names to declared run level - */ - Map serviceTypeRunLevels(); - - /** - * The declared {@code Scope} value for each service type. - * - * @return the map of service type names to declared scope name - */ - Map> serviceTypeScopeNames(); - - /** - * The set of {@link jakarta.inject.Qualifier}'s for each service type. - * - * @return the map of service type names to qualifiers - */ - Map> serviceTypeQualifiers(); - - /** - * The set of type names that the service type acts as an "is provider" for (i.e., {@link jakarta.inject.Provider}). - * - * @return the map of service type names to "is provider" flag values - */ - Map> serviceTypeToProviderForTypes(); - - /** - * The service type's interception plan. - * - * @return the map of service type names to the interception plan - */ - Map serviceTypeInterceptionPlan(); - - /** - * The extra source code that needs to be appended to the implementation. - * - * @return the map of service type names to the extra source code that should be added - */ - Map> extraCodeGen(); - - /** - * The extra source code class comments that needs to be appended to the implementation. - * - * @return the map of service type names to the extra source code class comments that should be added - */ - Map> extraClassComments(); - - /** - * The set of external modules used and/or required. - * - * @return the set of external modules used and/or required - */ - Set modulesRequired(); - - /** - * Typically populated as "test" if test scoped, otherwise left blank. - * - * @return production or test scope - */ - @ConfiguredOption(DEFAULT_CLASS_PREFIX_NAME) - String classPrefixName(); - - /** - * Used in conjunction with {@link ActivatorCreatorConfigOptions#moduleCreated()}. - * If a module is created and this set is - * populated then this set will be used to represent all {@link io.helidon.inject.api.Activator} type names that should be code - * generated for this {@link io.helidon.inject.api.ModuleComponent}. - * - * @return all module activator type names known for this given module being processed - */ - Set allModuleActivatorTypeNames(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorConfigOptionsBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorConfigOptionsBlueprint.java deleted file mode 100644 index d68933bfc3e..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorConfigOptionsBlueprint.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * These options are expected to have an affinity match to "permit" properties found within - * {@link io.helidon.inject.api.InjectionServicesConfig}. These are used to fine tune the type of code generated. - * - * @see io.helidon.inject.tools.spi.ActivatorCreator - */ -@Prototype.Blueprint -interface ActivatorCreatorConfigOptionsBlueprint { - /** - * Should jsr-330 be followed in strict accordance. The default here is actually set to false for two reasons: - *
    - *
  1. It is usually not what people expect (i.e., losing @inject on overridden injectable setter methods), and - *
  2. The implementation will e slightly more performant (i.e., the "rules" governing jsr-330 requires that base classes - * are injected prior to derived classes. This coupled with point 1 requires special additional book-keeping to be - * managed by the activators that are generated). - *
- * - * @return true if strict mode is in effect - */ - @ConfiguredOption("false") - boolean supportsJsr330InStrictMode(); - - /** - * Should a {@link io.helidon.inject.api.ModuleComponent} be created during activator creation. The default is true. - * - * @return true if the module should be created - */ - @ConfiguredOption("true") - boolean moduleCreated(); - - /** - * Should a stub {@link io.helidon.inject.api.Application} be created during activator creation. The default is false. - * This feature can opt'ed in by using {@code inject.application.pre.create}. Pre-req requires that this can - * only be enabled if {@link #moduleCreated()} is also enabled. - * - * @return true if the application should be created - */ - @ConfiguredOption("false") - boolean applicationPreCreated(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorDefault.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorDefault.java deleted file mode 100644 index eaf6bac23a2..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorDefault.java +++ /dev/null @@ -1,1303 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.stream.Collectors; - -import io.helidon.common.LazyValue; -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.common.processor.CopyrightHandler; -import io.helidon.common.processor.GeneratorTools; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.DeActivator; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.DependencyInfo; -import io.helidon.inject.api.DependencyInfoComparator; -import io.helidon.inject.api.ElementInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.RunLevel; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.runtime.AbstractServiceProvider; -import io.helidon.inject.runtime.Dependencies; -import io.helidon.inject.tools.spi.ActivatorCreator; - -import io.github.classgraph.AnnotationInfo; -import io.github.classgraph.ClassInfo; -import io.github.classgraph.MethodInfo; -import io.github.classgraph.MethodInfoList; -import io.github.classgraph.ScanResult; -import jakarta.inject.Singleton; - -import static io.helidon.inject.api.ServiceInfoBasics.DEFAULT_INJECT_WEIGHT; -import static io.helidon.inject.tools.TypeTools.componentTypeNameOf; -import static io.helidon.inject.tools.TypeTools.createTypeNameFromClassInfo; -import static io.helidon.inject.tools.TypeTools.isPackagePrivate; - -/** - * Responsible for building all di related collateral for a module, including: - *
    - *
  1. The {@link ServiceProvider} for each service type implementation passed in. - *
  2. The {@link Activator} and {@link DeActivator} for each service type - * implementation passed in. - *
  3. The {@link ModuleComponent} for the aggregate service provider bindings for the same set of service - * type names. - *
  4. The module-info as appropriate for the above set of services (and contracts). - *
  5. The /META-INF/services entries as appropriate. - *
- * - * This API can also be used to only produce meta-information describing the model without the codegen option - see - * {@link ActivatorCreatorRequest#codeGenPaths()} for details. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Singleton -@Weight(DEFAULT_INJECT_WEIGHT) -public class ActivatorCreatorDefault extends AbstractCreator implements ActivatorCreator, Weighted { - /** - * The suffix name for the service type activator class. - */ - static final String ACTIVATOR_NAME_SUFFIX = "Activator"; - /** - * The suffix for activator class name. - */ - public static final String INNER_ACTIVATOR_CLASS_NAME = "$$" + NAME_PREFIX + ACTIVATOR_NAME_SUFFIX; - private static final String SERVICE_PROVIDER_ACTIVATOR_HBS = "service-provider-activator.hbs"; - private static final String SERVICE_PROVIDER_APPLICATION_STUB_HBS = "service-provider-application-stub.hbs"; - private static final String SERVICE_PROVIDER_MODULE_HBS = "service-provider-module.hbs"; - private static final TypeName CREATOR = TypeName.create(ActivatorCreatorDefault.class); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public ActivatorCreatorDefault() { - super(TemplateHelper.DEFAULT_TEMPLATE_NAME); - } - - /** - * Applies to module-info. - */ - static TypeName toModuleTypeName(ActivatorCreatorRequest req, - List activatorTypeNames) { - String packageName; - if (CommonUtils.hasValue(req.packageName().orElse(null))) { - packageName = req.packageName().orElseThrow(); - } else { - if (activatorTypeNames == null || activatorTypeNames.isEmpty()) { - return null; - } - packageName = activatorTypeNames.get(0).packageName() + "." + NAME_PREFIX; - } - - String className = toModuleClassName(req.codeGen().classPrefixName()); - return TypeName.builder() - .packageName(packageName) - .className(className) - .build(); - } - - static String toModuleClassName(String modulePrefix) { - modulePrefix = (modulePrefix == null) ? "" : modulePrefix; - return NAME_PREFIX + modulePrefix + MODULE_NAME_SUFFIX; - } - - static Map> toMetaInfServices(ModuleDetail moduleDetail, - TypeName applicationTypeName, - boolean isApplicationCreated, - boolean isModuleCreated) { - Map> metaInfServices = new LinkedHashMap<>(); - if (isApplicationCreated && applicationTypeName != null) { - metaInfServices.put(TypeNames.INJECT_APPLICATION, - List.of(applicationTypeName.name())); - } - if (isModuleCreated && moduleDetail != null) { - metaInfServices.put(TypeNames.INJECT_MODULE, - List.of(moduleDetail.moduleTypeName().name())); - } - return metaInfServices; - } - - /** - * Creates a payload given the batch of services to process. - * - * @param services the services to process - * @return the payload, or empty if unable or nothing to process - */ - public static Optional createActivatorCreatorCodeGen(ServicesToProcess services) { - // do not generate activators for modules or applications... - List serviceTypeNames = services.serviceTypeNames(); - if (!serviceTypeNames.isEmpty()) { - TypeName applicationTypeName = TypeName.create(TypeNames.INJECT_APPLICATION); - TypeName moduleTypeName = TypeName.create(TypeNames.INJECT_MODULE); - serviceTypeNames = serviceTypeNames.stream() - .filter(typeName -> { - Set contracts = services.contracts().get(typeName); - if (contracts == null) { - return true; - } - return !contracts.contains(applicationTypeName) && !contracts.contains(moduleTypeName); - }) - .collect(Collectors.toList()); - } - if (serviceTypeNames.isEmpty()) { - return Optional.empty(); - } - - return Optional.of(ActivatorCreatorCodeGen.builder() - .serviceTypeToParentServiceTypes(services.parentServiceTypes()) - .serviceTypeToActivatorGenericDecl(services.activatorGenericDecls()) - .serviceTypeHierarchy(toFilteredHierarchy(services)) - .serviceTypeAccessLevels(services.accessLevels()) - .serviceTypeIsAbstractTypes(services.isAbstractMap()) - .serviceTypeContracts(toFilteredContracts(services)) - .serviceTypeExternalContracts(services.externalContracts()) - .serviceTypeInjectionPointDependencies(services.injectionPointDependencies()) - .serviceTypeDefaultConstructors(services.defaultConstructors()) - .serviceTypePostConstructMethodNames(services.postConstructMethodNames()) - .serviceTypePreDestroyMethodNames(services.preDestroyMethodNames()) - .serviceTypeWeights(services.weightedPriorities()) - .serviceTypeRunLevels(services.runLevels()) - .serviceTypeScopeNames(services.scopeTypeNames()) - .serviceTypeToProviderForTypes(services.providerForTypeNames()) - .serviceTypeQualifiers(services.qualifiers()) - .modulesRequired(services.requiredModules()) - .classPrefixName((services.lastKnownTypeSuffix() != null) - ? GeneratorTools.capitalize(services.lastKnownTypeSuffix()) - : ActivatorCreatorCodeGen.DEFAULT_CLASS_PREFIX_NAME) - .serviceTypeInterceptionPlan(services.interceptorPlans()) - .extraCodeGen(services.extraCodeGen()) - .extraClassComments(services.extraActivatorClassComments()) - .build()); - } - - /** - * Create a request based upon the contents of services to processor. - * - * @param servicesToProcess the batch being processed - * @param codeGen the code gen request - * @param configOptions the config options - * @param filer the filer - * @param throwIfError fail on error? - * @return the activator request instance - */ - public static ActivatorCreatorRequest createActivatorCreatorRequest(ServicesToProcess servicesToProcess, - ActivatorCreatorCodeGen codeGen, - ActivatorCreatorConfigOptions configOptions, - CodeGenFiler filer, - boolean throwIfError) { - String packageName = servicesToProcess.determineGeneratedPackageName(); - String moduleName = servicesToProcess.determineGeneratedModuleName(); - if (ModuleInfoDescriptor.DEFAULT_MODULE_NAME.equals(moduleName)) { - // last resort is using the application name as the module name - moduleName = packageName; - } - - CodeGenPaths codeGenPaths = createCodeGenPaths(servicesToProcess); - return ActivatorCreatorRequest.builder() - .serviceTypeNames(servicesToProcess.serviceTypeNames()) - .generatedServiceTypeNames(servicesToProcess.generatedServiceTypeNames()) - .codeGen(codeGen) - .codeGenPaths(codeGenPaths) - .filer(filer) - .configOptions(configOptions) - .throwIfError(throwIfError) - .moduleName(moduleName) - .packageName(packageName) - .build(); - } - - static ClassInfo toClassInfo(TypeName serviceTypeName, - LazyValue scan) { - ClassInfo classInfo = scan.get().getClassInfo(serviceTypeName.resolvedName()); - if (classInfo == null) { - throw new ToolsException("Unable to introspect: " + serviceTypeName); - } - return classInfo; - } - - static IdAndToString toBaseIdTag(MethodInfo m) { - String packageName = m.getClassInfo().getPackageName(); - boolean isPackagePrivate = isPackagePrivate(m.getModifiers()); - AccessModifier access = (isPackagePrivate) - ? AccessModifier.PACKAGE_PRIVATE : AccessModifier.PUBLIC; - String idTag = toBaseIdTagName(m.getName(), m.getParameterInfo().length, access, packageName); - return new IdAndToString(idTag, m); - } - - static String toBaseIdTagName(InjectionPointInfo ipInfo, - TypeName serviceTypeName) { - String packageName = serviceTypeName.packageName(); - return toBaseIdTagName(ipInfo.elementName(), ipInfo.elementArgs().orElse(0), ipInfo.access(), packageName); - } - - static String toBaseIdTagName(String methodName, - int methodArgCount, - AccessModifier access, - String packageName) { - return Dependencies.toMethodBaseIdentity(methodName, methodArgCount, access, packageName); - } - - /** - * Creates service info from the service type name and the activator create codegen request. - * - * @param serviceTypeName the service type name - * @param codeGen the code gen request - * @return the service info - */ - public static ServiceInfoBasics toServiceInfo(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Set contracts = codeGen.serviceTypeContracts().get(serviceTypeName); - contracts = contracts == null ? Set.of() : contracts; - Set externalContracts = codeGen.serviceTypeExternalContracts().get(serviceTypeName); - externalContracts = externalContracts == null ? Set.of() : externalContracts; - Set qualifiers = codeGen.serviceTypeQualifiers().get(serviceTypeName); - qualifiers = qualifiers == null ? Set.of() : qualifiers; - return ServiceInfo.builder() - .serviceTypeName(serviceTypeName) - .contractsImplemented(contracts) - .externalContractsImplemented(externalContracts) - .qualifiers(qualifiers) - .build(); - } - - static List serviceTypeHierarchy(TypeName serviceTypeName, - LazyValue scan) { - List order = new ArrayList<>(); - ClassInfo classInfo = toClassInfo(serviceTypeName, scan); - while (classInfo != null) { - order.add(0, createTypeNameFromClassInfo(classInfo)); - classInfo = classInfo.getSuperclass(); - } - return (1 == order.size()) ? List.of() : order; - } - - static String applicationClassName(String modulePrefix) { - modulePrefix = (modulePrefix == null) ? ActivatorCreatorCodeGen.DEFAULT_CLASS_PREFIX_NAME : modulePrefix; - return NAME_PREFIX + GeneratorTools.capitalize(modulePrefix) + "Application"; - } - - @Override - public ActivatorCreatorResponse createModuleActivators(ActivatorCreatorRequest req) throws ToolsException { - String templateName = (CommonUtils.hasValue(req.templateName())) ? req.templateName() : templateName(); - - ActivatorCreatorResponse.Builder builder = ActivatorCreatorResponse.builder() - .getConfigOptions(req.configOptions()) - .templateName(templateName); - - if (req.serviceTypeNames().isEmpty()) { - return handleError(req, new ToolsException("ServiceTypeNames is required to be passed"), builder); - } - - try { - LazyValue scan = LazyValue.create(ReflectionHandler.INSTANCE::scan); - return codegen(req, builder, scan); - } catch (ToolsException te) { - return handleError(req, te, builder); - } catch (UnsupportedOperationException e) { - throw e; - } catch (Throwable t) { - return handleError(req, new ToolsException("Failed in create", t), builder); - } - } - - ActivatorCreatorResponse codegen(ActivatorCreatorRequest req, - ActivatorCreatorResponse.Builder builder, - LazyValue scan) { - boolean isApplicationPreCreated = req.configOptions().applicationPreCreated(); - boolean isModuleCreated = req.configOptions().moduleCreated(); - CodeGenPaths codeGenPaths = req.codeGenPaths().orElse(null); - Map serviceTypeToIsAbstractType = req.codeGen().serviceTypeIsAbstractTypes(); - List activatorTypeNames = new ArrayList<>(); - Set activatorTypeNamesPutInModule = new TreeSet<>(req.codeGen().allModuleActivatorTypeNames()); - Map activatorDetails = new LinkedHashMap<>(); - for (TypeName serviceTypeName : req.generatedServiceTypeNames()) { - try { - ActivatorCodeGenDetail activatorDetail = createActivatorCodeGenDetail(req, serviceTypeName, scan); - Object prev = activatorDetails.put(serviceTypeName, activatorDetail); - assert (prev == null); - codegenActivatorFilerOut(req, activatorDetail); - TypeName activatorTypeName = toActivatorImplTypeName(serviceTypeName); - activatorTypeNames.add(activatorTypeName); - Boolean isAbstract = serviceTypeToIsAbstractType.get(serviceTypeName); - isAbstract = (isAbstract != null) && isAbstract; - if (!isAbstract) { - activatorTypeNamesPutInModule.add(activatorTypeName); - } - - InterceptionPlan interceptionPlan = req.codeGen().serviceTypeInterceptionPlan().get(serviceTypeName); - if (interceptionPlan != null) { - codegenInterceptorFilerOut(req, builder, interceptionPlan); - } - } catch (Exception e) { - throw new ToolsException("Failed to process: " + serviceTypeName, e); - } - } - builder.serviceTypeNames(activatorTypeNames) - .activatorTypeNamesPutInComponentModule(activatorTypeNamesPutInModule) - .serviceTypeDetails(activatorDetails); - - ModuleDetail moduleDetail; - TypeName applicationTypeName; - Map> metaInfServices; - TypeName moduleTypeName = toModuleTypeName(req, activatorTypeNames); - if (moduleTypeName != null) { - String className = applicationClassName(req.codeGen().classPrefixName()); - applicationTypeName = TypeName.builder() - .packageName(moduleTypeName.packageName()) - .className(className) - .build(); - builder.applicationTypeName(applicationTypeName); - String applicationStub = toApplicationStubBody(req, applicationTypeName, req.moduleName().orElse(null)); - if (isApplicationPreCreated && isModuleCreated) { - codegenApplicationFilerOut(req, applicationTypeName, applicationStub); - } - - moduleDetail = toModuleDetail(req, - activatorTypeNamesPutInModule, - moduleTypeName, - applicationTypeName, - isApplicationPreCreated, - isModuleCreated); - builder.moduleDetail(moduleDetail); - if (moduleDetail != null && isModuleCreated) { - codegenModuleFilerOut(req, moduleDetail); - Path outPath = codegenModuleInfoFilerOut(req, moduleDetail.descriptor().orElseThrow()); - logger().log(System.Logger.Level.DEBUG, "codegen module-info written to: " + outPath); - } - - metaInfServices = toMetaInfServices(moduleDetail, - applicationTypeName, - isApplicationPreCreated, - isModuleCreated); - builder.metaInfServices(metaInfServices); - if (!metaInfServices.isEmpty() && req.configOptions().moduleCreated()) { - codegenMetaInfServices(req, codeGenPaths, metaInfServices); - } - } - - return builder.build(); - } - - void codegenMetaInfServices(GeneralCreatorRequest req, - CodeGenPaths paths, - Map> metaInfServices) { - boolean prev = true; - if (req.analysisOnly()) { - prev = CodeGenFiler.filerWriterEnabled(false); - } - - try { - req.filer().codegenMetaInfServices(paths, metaInfServices); - } finally { - if (req.analysisOnly()) { - CodeGenFiler.filerWriterEnabled(prev); - } - } - } - - void codegenActivatorFilerOut(GeneralCreatorRequest req, - ActivatorCodeGenDetail activatorDetail) { - boolean prev = true; - if (req.analysisOnly()) { - prev = CodeGenFiler.filerWriterEnabled(false); - } - - try { - req.filer().codegenActivatorFilerOut(activatorDetail); - } finally { - if (req.analysisOnly()) { - CodeGenFiler.filerWriterEnabled(prev); - } - } - } - - void codegenModuleFilerOut(GeneralCreatorRequest req, - ModuleDetail moduleDetail) { - boolean prev = true; - if (req.analysisOnly()) { - prev = CodeGenFiler.filerWriterEnabled(false); - } - - try { - req.filer().codegenModuleFilerOut(moduleDetail); - } finally { - if (req.analysisOnly()) { - CodeGenFiler.filerWriterEnabled(prev); - } - } - } - - void codegenApplicationFilerOut(GeneralCreatorRequest req, - TypeName applicationTypeName, - String applicationBody) { - boolean prev = true; - if (req.analysisOnly()) { - prev = CodeGenFiler.filerWriterEnabled(false); - } - - try { - req.filer().codegenApplicationFilerOut(applicationTypeName, applicationBody); - } finally { - if (req.analysisOnly()) { - CodeGenFiler.filerWriterEnabled(prev); - } - } - } - - Path codegenModuleInfoFilerOut(GeneralCreatorRequest req, - ModuleInfoDescriptor descriptor) { - boolean prev = true; - if (req.analysisOnly()) { - prev = CodeGenFiler.filerWriterEnabled(false); - } - - try { - return req.filer().codegenModuleInfoFilerOut(descriptor, true).orElse(null); - } finally { - if (req.analysisOnly()) { - CodeGenFiler.filerWriterEnabled(prev); - } - } - } - - @Override - public InterceptorCreatorResponse codegenInterceptors(CodeGenInterceptorRequest request) { - InterceptorCreatorResponse.Builder res = InterceptorCreatorResponse.builder(); - res.interceptionPlans(request.interceptionPlans()); - - for (Map.Entry e : request.interceptionPlans().entrySet()) { - try { - Optional filePath = codegenInterceptorFilerOut(request.generalCreatorRequest(), null, e.getValue()); - filePath.ifPresent(it -> res.putGeneratedFile(e.getKey(), it)); - } catch (Throwable t) { - throw new ToolsException("Failed while processing: " + e.getKey(), t); - } - } - - return res.build(); - } - - String toApplicationStubBody(ActivatorCreatorRequest req, - TypeName applicationTypeName, - String moduleName) { - String template = templateHelper().safeLoadTemplate(req.templateName(), SERVICE_PROVIDER_APPLICATION_STUB_HBS); - - String generatedSticker = toGeneratedSticker(generatorType(req), - generatorType(req), // there is no specific type trigger for app - applicationTypeName); - - Map subst = new HashMap<>(); - subst.put("classname", applicationTypeName.className()); - subst.put("packagename", applicationTypeName.packageName()); - subst.put("description", "Generated Application."); - subst.put("generatedanno", generatedSticker); - TypeName generatorType = TypeName.create(getClass()); - subst.put("header", CopyrightHandler.copyright(generatorType, generatorType, applicationTypeName)); - subst.put("modulename", moduleName); - return templateHelper().applySubstitutions(template, subst, true).trim(); - } - - String toModuleBody(ActivatorCreatorRequest req, - String packageName, - String className, - String moduleName, - Set activatorTypeNames) { - String template = templateHelper().safeLoadTemplate(req.templateName(), SERVICE_PROVIDER_MODULE_HBS); - - String generatedSticker = toGeneratedSticker(generatorType(req), - generatorType(req), // there is no specific type trigger for module - TypeName.builder() - .packageName(packageName) - .className(className) - .build()); - - Map subst = new HashMap<>(); - subst.put("classname", className); - subst.put("packagename", packageName); - subst.put("description", "Generated ModuleComponent."); - subst.put("generatedanno", generatedSticker); - TypeName generatorType = TypeName.create(getClass()); - TypeName moduleType = TypeName.builder() - .packageName(packageName) - .className(className) - .build(); - subst.put("header", CopyrightHandler.copyright(generatorType, generatorType, moduleType)); - subst.put("modulename", moduleName); - subst.put("activators", activatorTypeNames); - - return templateHelper().applySubstitutions(template, subst, true).trim(); - } - - @Override - public TypeName toActivatorImplTypeName(TypeName serviceTypeName) { - return TypeName.builder() - .packageName(serviceTypeName.packageName()) - .enclosingNames(List.of()) - .className(CommonUtils.toFlatName(serviceTypeName.classNameWithEnclosingNames()) + INNER_ACTIVATOR_CLASS_NAME) - .build(); - } - - String toCodenParent(boolean ignoredIsSupportsJsr330InStrictMode, - TypeName activatorTypeName, - TypeName parentTypeName) { - - if (parentTypeName == null || Object.class.getName().equals(parentTypeName.name())) { - return AbstractServiceProvider.class.getName() + "<" + activatorTypeName.classNameWithEnclosingNames() + ">"; - } - - return parentTypeName.resolvedName(); - } - - List toCodegenDependencies(DependenciesInfo dependencies) { - if (dependencies == null) { - return null; - } - - List result = new ArrayList<>(); - dependencies.allDependencies() - .forEach(dep1 -> dep1.injectionPointDependencies() - .forEach(dep2 -> result.add(toCodegenDependency(dep1.dependencyTo(), dep2)))); - - return result; - } - - String toCodegenDependency(ServiceInfoCriteria dependencyTo, - InjectionPointInfo ipInfo) { - StringBuilder builder = new StringBuilder(); - //.add("world", World.class, InjectionPointInfo.ElementKind.FIELD, InjectionPointInfo.Access.PACKAGE_PRIVATE) - String elemName = CodeGenUtils.elementNameKindRef(ipInfo.elementName(), ipInfo.elementKind()); - builder.append(".add(").append(elemName).append(", "); - builder.append(Objects.requireNonNull(componentTypeNameOf(CommonUtils.first(dependencyTo.contractsImplemented(), true)))) - .append(".class, "); - builder.append("ElementKind.").append(Objects.requireNonNull(ipInfo.elementKind())).append(", "); - if (ElementKind.FIELD != ipInfo.elementKind()) { - builder.append(ipInfo.elementArgs().orElseThrow()).append(", "); - } - builder.append("AccessModifier.").append(Objects.requireNonNull(ipInfo.access())).append(")"); - Integer elemPos = ipInfo.elementArgs().orElse(null); - Integer elemOffset = ipInfo.elementOffset().orElse(null); - Set qualifiers = ipInfo.qualifiers(); - if (elemPos != null && elemOffset != null) { - builder.append(".elemOffset(").append(elemOffset).append(")"); - } - builder.append(".ipName(\"") - .append(ipInfo.ipName()) - .append("\")"); - builder.append(".ipType(io.helidon.common.types.TypeName.create(") - .append(ipInfo.ipType().genericTypeName().resolvedName()) - .append(".class))"); - if (!qualifiers.isEmpty()) { - builder.append(toCodegenQualifiers(qualifiers)); - } - if (ipInfo.listWrapped()) { - builder.append(".listWrapped()"); - } - if (ipInfo.providerWrapped()) { - builder.append(".providerWrapped()"); - } - if (ipInfo.optionalWrapped()) { - builder.append(".optionalWrapped()"); - } - if (ipInfo.staticDeclaration()) { - builder.append(".staticDeclaration()"); - } - return builder.toString(); - } - - String toCodegenQualifiers(Collection qualifiers) { - StringBuilder builder = new StringBuilder(); - for (Qualifier qualifier : qualifiers) { - if (builder.length() > 0) { - builder.append("\n\t\t\t"); - } - builder.append(".addQualifier(").append(toCodegenQualifiers(qualifier)).append(")"); - } - return builder.toString(); - } - - String toCodegenQualifiers(Qualifier qualifier) { - String val = toCodegenQuotedString(qualifier.value().orElse(null)); - String result = Qualifier.class.getName() + ".create(" - + qualifier.qualifierTypeName() + ".class"; - if (val != null) { - result += ", " + val; - } - result += ")"; - return result; - } - - String toCodegenQuotedString(String value) { - return (value == null) ? null : "\"" + value + "\""; - } - - String toCodegenDecl(ServiceInfoCriteria dependencyTo, - InjectionPointInfo injectionPointInfo) { - TypeName contract = CommonUtils.first(dependencyTo.contractsImplemented(), true); - StringBuilder builder = new StringBuilder(); - if (injectionPointInfo.optionalWrapped()) { - builder.append("Optional<").append(contract).append(">"); - } else { - if (injectionPointInfo.listWrapped()) { - builder.append("List<"); - } - if (injectionPointInfo.providerWrapped()) { - builder.append("Provider<"); - } - builder.append(contract); - if (injectionPointInfo.providerWrapped()) { - builder.append(">"); - } - if (injectionPointInfo.listWrapped()) { - builder.append(">"); - } - } - InjectionSupported.isSupportedInjectionPoint(logger(), - injectionPointInfo.serviceTypeName(), - injectionPointInfo, - AccessModifier.PRIVATE == injectionPointInfo.access(), - injectionPointInfo.staticDeclaration()); - return builder.toString(); - } - - String toCodegenCtorArgList(DependenciesInfo dependencies) { - if (dependencies == null) { - return null; - } - - AtomicReference nameRef = new AtomicReference<>(); - List args = new ArrayList<>(); - dependencies.allDependencies() - .forEach(dep1 -> dep1.injectionPointDependencies() - .stream() - .filter(dep2 -> InjectionPointInfo.CONSTRUCTOR.equals(dep2.elementName())) - .forEach(dep2 -> { - if (nameRef.get() == null) { - nameRef.set(dep2.baseIdentity()); - } else { - assert (nameRef.get().equals(dep2.baseIdentity())) - : "only one Constructor can be injectable: " + dependencies.fromServiceTypeName(); - } - args.add(dep2.ipName()); - }) - ); - - return (args.isEmpty()) ? null : CommonUtils.toString(args); - } - - List toCodegenInjectCtorArgs(DependenciesInfo dependencies) { - if (dependencies == null) { - return null; - } - - AtomicReference nameRef = new AtomicReference<>(); - List args = new ArrayList<>(); - List allCtorArgs = dependencies.allDependenciesFor(InjectionPointInfo.CONSTRUCTOR); - allCtorArgs.forEach(dep1 -> dep1.injectionPointDependencies() - .forEach(dep2 -> { - if (nameRef.get() == null) { - nameRef.set(dep2.baseIdentity()); - } else { - assert (nameRef.get().equals(dep2.baseIdentity())) : "only 1 constructor can be injectable"; - } - // fully qualified type of the injection point, as we are assigning to it - String cn = dep2.ipType().resolvedName(); - String argName = dep2.ipName(); - String id = dep2.id(); - String argBuilder = cn + " " - + argName + " = (" + cn + ") " - + "get(deps, \"" + id + "\");"; - args.add(argBuilder); - })); - return args; - } - - List toCodegenInjectFields(DependenciesInfo dependencies) { - if (dependencies == null) { - return null; - } - - List fields = new ArrayList<>(); - dependencies.allDependencies() - .forEach(dep1 -> dep1.injectionPointDependencies().stream() - .filter(dep2 -> ElementKind.FIELD - .equals(dep2.elementKind())) - .forEach(dep2 -> { - String cn = toCodegenDecl(dep1.dependencyTo(), dep2); - IdAndToString setter; - String id = dep2.id(); - if (Void.class.getName().equals(cn)) { - setter = new IdAndToString(id, dep2.elementName()); - } else { - setter = new IdAndToString(id, dep2.elementName() - + " = (" + cn + ") get(deps, \"" - + dep2.baseIdentity() + "\")"); - } - fields.add(setter); - })); - return fields; - } - - List toCodegenInjectMethods(TypeName serviceTypeName, - DependenciesInfo dependencies) { - if (dependencies == null) { - return null; - } - - List methods = new ArrayList<>(); - String lastElemName = null; - String lastId = null; - List compositeSetter = null; - List allDeps = dependencies.allDependencies().stream() - .filter(it -> it.injectionPointDependencies().iterator().next().elementKind() == ElementKind.METHOD) - .collect(Collectors.toList()); - if (allDeps.size() > 1) { - allDeps.sort(DependencyInfoComparator.instance()); - } - - for (DependencyInfo dep1 : allDeps) { - for (InjectionPointInfo ipInfo : dep1.injectionPointDependencies()) { - if (ipInfo.elementKind() != ElementKind.METHOD) { - continue; - } - - String id = toBaseIdTagName(ipInfo, serviceTypeName); - String elemName = ipInfo.elementName(); - Integer elemPos = ipInfo.elementOffset().orElse(null); - int elemArgs = ipInfo.elementArgs().orElse(0); - String cn = toCodegenDecl(dep1.dependencyTo(), ipInfo); - - if (lastId != null && !lastId.equals(id) && compositeSetter != null) { - IdAndToString setter = new IdAndToString(lastId, lastElemName + "(" - + CommonUtils.toString(compositeSetter, null, ",\n\t\t\t\t") - + ")"); - methods.add(setter); - compositeSetter = null; - } - - if (0 == elemArgs) { - assert (Void.class.getName().equals(cn)); - IdAndToString setter = new IdAndToString(id, elemName + "()"); - methods.add(setter); - } else if (1 == elemArgs) { - assert (elemArgs == elemPos); - IdAndToString setter = new IdAndToString(id, - elemName + "((" + cn + ") get(deps, \"" + id + "(1)\"))"); - methods.add(setter); - } else { - assert (elemArgs > 1); - if (compositeSetter == null) { - compositeSetter = new ArrayList<>(); - } - compositeSetter.add("(" + cn + ") get(deps, \"" + id + "(" + elemPos + ")\")"); - } - - lastId = id; - lastElemName = elemName; - } - } - - if (compositeSetter != null) { - IdAndToString setter = new IdAndToString(lastId, lastElemName + "(" - + CommonUtils.toString(compositeSetter, null, ",\n\t\t\t\t") - + ")"); - methods.add(setter); - } - - return methods; - } - - Collection toCodegenInjectMethodsSkippedInParent(boolean isSupportsJsr330InStrictMode, - TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen, - LazyValue scan) { - List hierarchy = codeGen.serviceTypeHierarchy().get(serviceTypeName); - TypeName parent = parentOf(serviceTypeName, codeGen); - if (hierarchy == null && parent != null) { - hierarchy = List.of(parent); - } - if (hierarchy == null) { - return List.of(); - } - - DependenciesInfo deps = codeGen.serviceTypeInjectionPointDependencies().get(serviceTypeName); - - Set result = new LinkedHashSet<>(); - hierarchy.stream().filter((typeName) -> !serviceTypeName.equals(typeName)) - .forEach(parentTypeName -> { - DependenciesInfo parentDeps = codeGen.serviceTypeInjectionPointDependencies().get(parentTypeName); - List skipList = toCodegenInjectMethodsSkippedInParent(isSupportsJsr330InStrictMode, - serviceTypeName, - deps, - parentTypeName, - parentDeps, - scan); - if (skipList != null) { - result.addAll(skipList); - } - }); - - return result; - } - - /** - * Called in strict Jsr330 compliance mode. If Inject anno is on parent method but not on child method - * then we should hide the inject in the parent. Crazy that inject was not inherited if you ask me! - * - * @param isSupportsJsr330InStrictMode are we in jsr-330 strict mode - * @param serviceTypeName the activator service type name - * @param dependencies the dependencies for this service type - * @param parentTypeName the parent type - * @param parentDependencies the parent dependencies - * @param scan the provider of class introspection - * @return the list of injection point identifiers that should be skipped in the parent delegation call - */ - List toCodegenInjectMethodsSkippedInParent(boolean isSupportsJsr330InStrictMode, - TypeName serviceTypeName, - DependenciesInfo dependencies, - TypeName parentTypeName, - DependenciesInfo parentDependencies, - LazyValue scan) { - if (!isSupportsJsr330InStrictMode || parentTypeName == null) { - return null; - } - - ClassInfo classInfo = toClassInfo(serviceTypeName, scan); - ClassInfo parentClassInfo = toClassInfo(parentTypeName, scan); - MethodInfoList parentMethods = parentClassInfo.getDeclaredMethodInfo(); - Map injectedParentMethods = parentMethods.stream() - .filter(m -> (m.getAnnotationInfo(TypeNames.JAKARTA_INJECT) != null)) - .filter(m -> ExternalModuleCreatorDefault.isInjectionSupported(parentTypeName, m, logger())) - .collect(Collectors.toMap(ActivatorCreatorDefault::toBaseIdTag, Function.identity())); - if (injectedParentMethods.isEmpty()) { - return null; - } - - MethodInfoList methods = classInfo.getDeclaredMethodInfo(); - Map allSupportedMethodsOnServiceType = methods.stream() - .filter(m -> ExternalModuleCreatorDefault.isInjectionSupported(serviceTypeName, m, logger())) - .collect(Collectors.toMap(ActivatorCreatorDefault::toBaseIdTag, Function.identity())); - - List removeList = null; - - for (Map.Entry e : injectedParentMethods.entrySet()) { - MethodInfo method = allSupportedMethodsOnServiceType.get(e.getKey()); - if (method != null) { - AnnotationInfo annotationInfo = method.getAnnotationInfo(TypeNames.JAKARTA_INJECT); - if (annotationInfo != null) { - continue; - } - if (removeList == null) { - removeList = new ArrayList<>(); - } - removeList.add(e.getKey()); - } - } - - return removeList; - } - - Double toWeightedPriority(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Double weight = codeGen.serviceTypeWeights().get(serviceTypeName); - if (weight == null && hasParent(serviceTypeName, codeGen)) { - // we might be a child of another service, in which case we will need to override its value - weight = Weighted.DEFAULT_WEIGHT; - } - return weight; - } - - Integer toRunLevel(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Integer runLevel = codeGen.serviceTypeRunLevels().get(serviceTypeName); - if (runLevel == null && hasParent(serviceTypeName, codeGen)) { - // we might be a child of another service, in which case we will need to override its value - runLevel = RunLevel.NORMAL; - } - return runLevel; - } - - boolean hasParent(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - return (parentOf(serviceTypeName, codeGen) != null); - } - - TypeName parentOf(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - return codeGen.serviceTypeToParentServiceTypes().get(serviceTypeName); - } - - List toDescription(TypeName serviceTypeName) { - return List.of("Activator for {@link " + serviceTypeName + "}."); - } - - TypeName toActivatorTypeName(TypeName serviceTypeName) { - return serviceTypeName; - } - - TypeName toParentTypeName(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - return codeGen.serviceTypeToParentServiceTypes().get(serviceTypeName); - } - - String toActivatorGenericDecl(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - return codeGen.serviceTypeToActivatorGenericDecl().get(serviceTypeName); - } - - Set toScopeTypeNames(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Set result = codeGen.serviceTypeScopeNames().get(serviceTypeName); - return (result == null) ? Set.of() : result; - } - - /** - * One might expect that isProvider should only be set to true if the service type implements Provider<>. However, - * that alone would fail JSR-330 testing. The interpretation there is any service without a scope is inferred to be - * non-singleton, provided/dependent scope. - */ - boolean toIsProvider(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Set scopeTypeName = toScopeTypeNames(serviceTypeName, codeGen); - if ((scopeTypeName == null || scopeTypeName.isEmpty()) && toIsConcrete(serviceTypeName, codeGen)) { - return true; - } - - Set providerFor = codeGen.serviceTypeToProviderForTypes().get(serviceTypeName); - return (providerFor != null) && !providerFor.isEmpty(); - } - - boolean toIsConcrete(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Boolean isAbstract = codeGen.serviceTypeIsAbstractTypes().get(serviceTypeName); - return (isAbstract == null) || !isAbstract; - } - - DependenciesInfo toDependencies(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - if (serviceTypeName == null) { - return null; - } - - return codeGen.serviceTypeInjectionPointDependencies().get(serviceTypeName); - } - - String toConstructor(TypeName serviceTypeName, ActivatorCreatorCodeGen codeGen, String className) { - String constructor = codeGen.serviceTypeDefaultConstructors().get(serviceTypeName); - if (constructor == null) { - return "serviceInfo(serviceInfo);\n"; - } - return constructor.replaceAll("\\{\\{className}}", className); - } - - String toPostConstructMethodName(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - return codeGen.serviceTypePostConstructMethodNames().get(serviceTypeName); - } - - String toPreDestroyMethodName(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - return codeGen.serviceTypePreDestroyMethodNames().get(serviceTypeName); - } - - List toServiceTypeHierarchy(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen, - LazyValue scan) { - Map> map = codeGen.serviceTypeHierarchy(); - List order = (map != null) ? map.get(serviceTypeName) : null; - if (order != null) { - return (1 == order.size()) ? List.of() : order; - } - - return serviceTypeHierarchy(serviceTypeName, scan); - } - - List toExtraCodeGen(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Map> map = codeGen.extraCodeGen(); - List extraCodeGen = (map != null) ? map.get(serviceTypeName) : List.of(); - return (extraCodeGen == null) ? List.of() : extraCodeGen; - } - - List toExtraClassComments(TypeName serviceTypeName, - ActivatorCreatorCodeGen codeGen) { - Map> map = codeGen.extraClassComments(); - List extraClassComments = (map != null) ? map.get(serviceTypeName) : List.of(); - return (extraClassComments == null) ? List.of() : extraClassComments; - } - - ActivatorCreatorResponse handleError(ActivatorCreatorRequest request, - ToolsException e, - ActivatorCreatorResponse.Builder builder) { - if (request.throwIfError()) { - throw e; - } - - return builder - .error(e) - .success(false) - .build(); - } - - private static Map> toFilteredHierarchy(ServicesToProcess services) { - Map> hierarchy = services.serviceTypeToHierarchy(); - Map> filteredHierarchy = new LinkedHashMap<>(); - for (Map.Entry> e : hierarchy.entrySet()) { - List filtered = e.getValue().stream() - .filter((typeName) -> services.serviceTypeNames().contains(typeName)) - .collect(Collectors.toList()); - // assert (!filtered.isEmpty()) : e; - filteredHierarchy.put(e.getKey(), filtered); - } - return filteredHierarchy; - } - - private static Map> toFilteredContracts(ServicesToProcess services) { - Map> contracts = services.contracts(); - Map> filteredContracts = new LinkedHashMap<>(); - for (Map.Entry> e : contracts.entrySet()) { - Set contractsForThisService = e.getValue(); - Set externalContractsForThisService = services.externalContracts().get(e.getKey()); - if (externalContractsForThisService == null || externalContractsForThisService.isEmpty()) { - filteredContracts.put(e.getKey(), e.getValue()); - } else { - Set filteredContractsForThisService = new LinkedHashSet<>(contractsForThisService); - filteredContractsForThisService.removeAll(externalContractsForThisService); - filteredContracts.put(e.getKey(), filteredContractsForThisService); - } - } - return filteredContracts; - } - - private ModuleDetail toModuleDetail(ActivatorCreatorRequest req, - Set activatorTypeNamesPutInModule, - TypeName moduleTypeName, - TypeName applicationTypeName, - boolean isApplicationCreated, - boolean isModuleCreated) { - String className = moduleTypeName.className(); - String packageName = moduleTypeName.packageName(); - String moduleName = req.moduleName().orElse(null); - - ActivatorCreatorCodeGen codeGen = req.codeGen(); - String typePrefix = codeGen.classPrefixName(); - List modulesRequired = List.copyOf(codeGen.modulesRequired()); - Map> serviceTypeContracts = codeGen.serviceTypeContracts(); - Map> externalContracts = codeGen.serviceTypeExternalContracts(); - - Optional moduleInfoPath = Optional.empty(); - if (req.codeGenPaths().isPresent()) { - moduleInfoPath = req.codeGenPaths().get().moduleInfoPath(); - } - ModuleInfoCreatorRequest moduleCreatorRequest = ModuleInfoCreatorRequest.builder() - .name(moduleName) - .moduleTypeName(moduleTypeName) - .applicationTypeName(applicationTypeName) - .modulesRequired(modulesRequired) - .contracts(serviceTypeContracts) - .externalContracts(externalContracts) - .moduleInfoPath(moduleInfoPath) - .classPrefixName(typePrefix) - .applicationCreated(isApplicationCreated) - .moduleCreated(isModuleCreated) - .build(); - ModuleInfoDescriptor moduleInfo = createModuleInfo(moduleCreatorRequest); - moduleName = moduleInfo.name(); - String moduleBody = toModuleBody(req, packageName, className, moduleName, activatorTypeNamesPutInModule); - return ModuleDetail.builder() - .moduleName(moduleName) - .moduleTypeName(moduleTypeName) - .serviceProviderActivatorTypeNames(activatorTypeNamesPutInModule) - .moduleBody(moduleBody) - .moduleInfoBody(moduleInfo.contents()) - .descriptor(moduleInfo) - .build(); - } - - private Optional codegenInterceptorFilerOut(GeneralCreatorRequest req, - ActivatorCreatorResponse.Builder builder, - InterceptionPlan interceptionPlan) { - validate(interceptionPlan); - TypeName interceptorTypeName = InterceptorCreatorDefault.createInterceptorSourceTypeName(interceptionPlan); - InterceptorCreatorDefault interceptorCreator = new InterceptorCreatorDefault(); - String body = interceptorCreator.createInterceptorSourceBody(interceptionPlan); - if (builder != null) { - builder.putServiceTypeInterceptorPlan(interceptorTypeName, interceptionPlan); - } - return req.filer().codegenJavaFilerOut(interceptorTypeName, body); - } - - private void validate(InterceptionPlan plan) { - List ctorElements = plan.interceptedElements().stream() - .map(InterceptedElement::elementInfo) - .filter(it -> it.elementKind() == ElementKind.CONSTRUCTOR) - .collect(Collectors.toList()); - if (ctorElements.size() > 1) { - throw new IllegalStateException("Can only have interceptor with a single (injectable) constructor for: " - + plan.interceptedService().serviceTypeName()); - } - } - - private ActivatorCodeGenDetail createActivatorCodeGenDetail(ActivatorCreatorRequest req, - TypeName serviceTypeName, - LazyValue scan) { - ActivatorCreatorCodeGen codeGen = req.codeGen(); - String template = templateHelper().safeLoadTemplate(req.templateName(), SERVICE_PROVIDER_ACTIVATOR_HBS); - ServiceInfoBasics serviceInfo = toServiceInfo(serviceTypeName, codeGen); - TypeName activatorTypeName = toActivatorTypeName(serviceTypeName); - TypeName parentTypeName = toParentTypeName(serviceTypeName, codeGen); - String activatorGenericDecl = toActivatorGenericDecl(serviceTypeName, codeGen); - DependenciesInfo dependencies = toDependencies(serviceTypeName, codeGen); - DependenciesInfo parentDependencies = toDependencies(parentTypeName, codeGen); - Set scopeTypeNames = toScopeTypeNames(serviceTypeName, codeGen); - List description = toDescription(serviceTypeName); - Double weightedPriority = toWeightedPriority(serviceTypeName, codeGen); - Integer runLevel = toRunLevel(serviceTypeName, codeGen); - String constructor = toConstructor(serviceTypeName, codeGen, activatorTypeName.className()); - String postConstructMethodName = toPostConstructMethodName(serviceTypeName, codeGen); - String preDestroyMethodName = toPreDestroyMethodName(serviceTypeName, codeGen); - List serviceTypeInjectionOrder = toServiceTypeHierarchy(serviceTypeName, codeGen, scan); - List extraCodeGen = toExtraCodeGen(serviceTypeName, codeGen); - List extraClassComments = toExtraClassComments(serviceTypeName, codeGen); - boolean isProvider = toIsProvider(serviceTypeName, codeGen); - boolean isConcrete = toIsConcrete(serviceTypeName, codeGen); - boolean isSupportsJsr330InStrictMode = req.configOptions().supportsJsr330InStrictMode(); - Collection injectionPointsSkippedInParent = - toCodegenInjectMethodsSkippedInParent(isSupportsJsr330InStrictMode, activatorTypeName, codeGen, scan); - TypeName generatedType = toActivatorImplTypeName(activatorTypeName); - String generatedSticker = toGeneratedSticker(generatorType(req), - serviceTypeName, - generatedType); - - ActivatorCreatorArgs args = ActivatorCreatorArgs.builder() - .template(template) - .constructor(constructor) - .serviceTypeName(serviceTypeName) - .activatorTypeName(activatorTypeName) - .activatorGenericDecl(Optional.ofNullable(activatorGenericDecl)) - .parentTypeName(Optional.ofNullable(parentTypeName)) - .scopeTypeNames(scopeTypeNames) - .description(description) - .serviceInfo(serviceInfo) - .dependencies(Optional.ofNullable(dependencies)) - .parentDependencies(Optional.ofNullable(parentDependencies)) - .injectionPointsSkippedInParent(injectionPointsSkippedInParent) - .serviceTypeInjectionOrder(serviceTypeInjectionOrder) - .generatedSticker(generatedSticker) - .weightedPriority(Optional.ofNullable(weightedPriority)) - .runLevel(Optional.ofNullable(runLevel)) - .postConstructMethodName(Optional.ofNullable(postConstructMethodName)) - .preDestroyMethodName(Optional.ofNullable(preDestroyMethodName)) - .extraCodeGen(extraCodeGen) - .extraClassComments(extraClassComments) - .isConcrete(isConcrete) - .isProvider(isProvider) - .isSupportsJsr330InStrictMode(isSupportsJsr330InStrictMode) - .build(); - String activatorBody = toActivatorBody(args); - - return ActivatorCodeGenDetail.builder() - .serviceInfo(serviceInfo) - .dependencies(Optional.ofNullable(dependencies)) - .serviceTypeName(toActivatorImplTypeName(activatorTypeName)) - .body(activatorBody) - .build(); - } - - private TypeName generatorType(ActivatorCreatorRequest req) { - return req.generator().map(TypeName::create).orElse(CREATOR); - } - - private String toActivatorBody(ActivatorCreatorArgs args) { - TypeName processor = TypeName.create(getClass()); - Map subst = new HashMap<>(); - subst.put("header", CopyrightHandler.copyright(processor, args.serviceTypeName(), args.activatorTypeName())); - subst.put("activatorsuffix", INNER_ACTIVATOR_CLASS_NAME); - subst.put("constructor", args.constructor()); - subst.put("classname", args.activatorTypeName().classNameWithEnclosingNames()); - subst.put("flatclassname", CommonUtils.toFlatName(args.activatorTypeName().classNameWithEnclosingNames())); - subst.put("packagename", args.activatorTypeName().packageName()); - subst.put("activatorgenericdecl", args.activatorGenericDecl().orElse(null)); - subst.put("parent", toCodenParent(args.isSupportsJsr330InStrictMode(), - args.activatorTypeName(), args.parentTypeName().orElse(null))); - subst.put("scopetypenames", args.scopeTypeNames()); - subst.put("description", args.description()); - subst.put("generatedanno", args.generatedSticker()); - subst.put("isprovider", args.isProvider()); - subst.put("isconcrete", args.isConcrete()); - subst.put("contracts", args.serviceInfo().contractsImplemented()); - if (args.serviceInfo() instanceof ServiceInfo) { - ServiceInfo serviceInfo = ((ServiceInfo) args.serviceInfo()); - Set extContracts = serviceInfo.externalContractsImplemented(); - subst.put("externalcontracts", extContracts.stream() - .map(TypeName::resolvedName) - .toList()); - // there is no need to list these twice, since external contracts will implicitly back-full into contracts - subst.put("contracts", args.serviceInfo().contractsImplemented().stream() - .filter(it -> !extContracts.contains(it)) - .map(TypeName::resolvedName) - .collect(Collectors.toList())); - } - subst.put("qualifiers", toCodegenQualifiers(args.serviceInfo().qualifiers())); - subst.put("dependencies", toCodegenDependencies(args.dependencies().orElse(null))); - subst.put("weight", args.weightedPriority().orElse(null)); - subst.put("isweightset", args.weightedPriority().isPresent()); - subst.put("runlevel", args.runLevel().orElse(null)); - subst.put("isrunlevelset", args.runLevel().isPresent()); - subst.put("postconstruct", args.postConstructMethodName().orElse(null)); - subst.put("predestroy", args.preDestroyMethodName().orElse(null)); - subst.put("ctorarglist", toCodegenCtorArgList(args.dependencies().orElse(null))); - subst.put("ctorargs", toCodegenInjectCtorArgs(args.dependencies().orElse(null))); - subst.put("injectedfields", toCodegenInjectFields(args.dependencies().orElse(null))); - subst.put("injectedmethods", toCodegenInjectMethods(args.activatorTypeName(), args.dependencies().orElse(null))); - subst.put("injectedmethodsskippedinparent", args.injectionPointsSkippedInParent()); - subst.put("extracodegen", args.extraCodeGen()); - subst.put("extraclasscomments", args.extraClassComments()); - subst.put("injectionorder", args.serviceTypeInjectionOrder()); - subst.put("issupportsjsr330instrictmode", args.isSupportsJsr330InStrictMode()); - - logger().log(System.Logger.Level.DEBUG, "dependencies for " - + args.serviceTypeName() + " == " + args.dependencies()); - - return templateHelper().applySubstitutions(args.template(), subst, true).trim(); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorProvider.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorProvider.java deleted file mode 100644 index 659eb7b3a80..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.ServiceLoader; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.common.LazyValue; -import io.helidon.inject.tools.spi.ActivatorCreator; - -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -/** - * Provides access to the global singleton {@link ActivatorCreator} in use. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Singleton -public class ActivatorCreatorProvider implements Provider { - private static final LazyValue INSTANCE = LazyValue.create(ActivatorCreatorProvider::load); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public ActivatorCreatorProvider() { - } - - private static ActivatorCreator load() { - return HelidonServiceLoader.create(ServiceLoader.load(ActivatorCreator.class, ActivatorCreator.class.getClassLoader())) - .asList() - .stream() - .findFirst().orElseThrow(); - } - - // note that this is guaranteed to succeed since the default implementation is in this module - @Override - public ActivatorCreator get() { - return INSTANCE.get(); - } - - /** - * Returns the global instance that was service loaded. Note that this call is guaranteed to return a result since the - * default implementation is here in this module. - * - * @return the global service instance with the highest weight - */ - public static ActivatorCreator instance() { - return INSTANCE.get(); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorRequestBlueprint.java deleted file mode 100644 index b313c9e712a..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorRequestBlueprint.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.builder.api.Prototype; - -/** - * Request used in conjunction with {@link io.helidon.inject.tools.spi.ActivatorCreator} to codegen the - * {@link io.helidon.inject.api.Activator} source artifacts. - */ -@Prototype.Blueprint -interface ActivatorCreatorRequestBlueprint extends GeneralCreatorRequestBlueprint { - - /** - * Mandatory, identifies what specifically should be generated. - * - * @return identifies what should be generated - */ - ActivatorCreatorCodeGen codeGen(); - - /** - * The configuration directives to apply during generation. - * - * @return configuration directives used for code generation - */ - ActivatorCreatorConfigOptions configOptions(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorResponseBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorResponseBlueprint.java deleted file mode 100644 index bf8a10bc4d5..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorResponseBlueprint.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * The result of calling {@link io.helidon.inject.tools.spi.ActivatorCreator} assuming no errors are thrown. - */ -@Prototype.Blueprint -interface ActivatorCreatorResponseBlueprint extends GeneralCreatorResponseBlueprint { - - /** - * The configuration options that were applied. - * - * @return config options - */ - ActivatorCreatorConfigOptions getConfigOptions(); - - /** - * Return the interceptors that were generated. - * - * @return interceptors generated - */ - @Option.Singular - Map serviceTypeInterceptorPlans(); - - /** - * The activator types placed in the generated {@link io.helidon.inject.api.ModuleComponent}. - * - * @return the activator type names placed in the module component - */ - Set activatorTypeNamesPutInComponentModule(); - - /** - * The module-info detail, if a module was created. - * - * @return any module-info detail created - */ - Optional moduleDetail(); - - /** - * Set if the application stub was requested to have been created. - * - * @return the application name that was created - */ - Optional applicationTypeName(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorCodeGenBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorCodeGenBlueprint.java deleted file mode 100644 index 0abd3b7f8c8..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorCodeGenBlueprint.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Codegen request options applicable for {@link io.helidon.inject.tools.spi.ApplicationCreator}. - * - * @see io.helidon.inject.tools.spi.ApplicationCreator - */ -@Prototype.Blueprint -interface ApplicationCreatorCodeGenBlueprint { - - /** - * The package name to use for code generation. - * - * @return package name - */ - Optional packageName(); - - /** - * The class name to use for code generation. - * - * @return class name - */ - Optional className(); - - /** - * Typically populated as "test" if test scoped, otherwise left blank. - * - * @return production or test scope - */ - @ConfiguredOption("") - String classPrefixName(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorConfigOptionsBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorConfigOptionsBlueprint.java deleted file mode 100644 index c5f038dc5e4..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorConfigOptionsBlueprint.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Configuration directives and options optionally provided to the {@link io.helidon.inject.tools.spi.ApplicationCreator}. - */ -@Prototype.Blueprint -interface ApplicationCreatorConfigOptionsBlueprint { - /** - * The default permitted provider type. - */ - PermittedProviderType DEFAULT_PERMITTED_PROVIDER_TYPE = PermittedProviderType.ALL; - - /** - * Determines the application generator's tolerance around the usage of providers. - * - * @return provider generation permission type - */ - @ConfiguredOption("ALL") - PermittedProviderType permittedProviderTypes(); - - /** - * Only applicable when {@link #permittedProviderTypes()} is set to - * {@link PermittedProviderType#NAMED}. This is the set of provider names that are explicitly - * permitted to be generated. - * - * @return the allow-listed named providers (which is the FQN of the underlying service type) - */ - @Option.Singular - Set permittedProviderNames(); - - /** - * Only applicable when {@link #permittedProviderTypes()} is set to - * {@link PermittedProviderType#NAMED}. This is the set of qualifier types that are explicitly - * permitted to be generated. - * - * @return the allow-listed qualifier type names - */ - @Option.Singular - Set permittedProviderQualifierTypeNames(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorDefault.java b/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorDefault.java deleted file mode 100644 index b70f46b8269..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorDefault.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.File; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.common.Weight; -import io.helidon.common.processor.CopyrightHandler; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.InjectionException; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.runtime.AbstractServiceProvider; -import io.helidon.inject.runtime.HelidonInjectionPlan; -import io.helidon.inject.runtime.ServiceBinderDefault; -import io.helidon.inject.tools.spi.ApplicationCreator; - -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -import static io.helidon.inject.api.ServiceInfoBasics.DEFAULT_INJECT_WEIGHT; -import static io.helidon.inject.runtime.ServiceUtils.isQualifiedInjectionTarget; - -/** - * The default implementation for {@link ApplicationCreator}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Singleton -@Weight(DEFAULT_INJECT_WEIGHT) -public class ApplicationCreatorDefault extends AbstractCreator implements ApplicationCreator { - /** - * The prefix to add before the generated "Application" class name (i.e., "Injection$$" in the "Injection$$Application"). - */ - public static final String NAME_PREFIX = AbstractCreator.NAME_PREFIX; - - /** - * The "Application" part of the name. - */ - public static final String APPLICATION_NAME_SUFFIX = "Application"; - - /** - * The FQN "Injection$$Application" name. - */ - public static final String APPLICATION_NAME = NAME_PREFIX + APPLICATION_NAME_SUFFIX; - - static final String SERVICE_PROVIDER_APPLICATION_SERVICETYPEBINDING_HBS - = "service-provider-application-servicetypebinding.hbs"; - static final String SERVICE_PROVIDER_APPLICATION_EMPTY_SERVICETYPEBINDING_HBS - = "service-provider-application-empty-servicetypebinding.hbs"; - static final String SERVICE_PROVIDER_APPLICATION_HBS - = "service-provider-application.hbs"; - private static final TypeName CREATOR = TypeName.create(ApplicationCreatorDefault.class); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public ApplicationCreatorDefault() { - super(TemplateHelper.DEFAULT_TEMPLATE_NAME); - } - - static boolean isAllowListedProviderName(ApplicationCreatorConfigOptions configOptions, - TypeName typeName) { - PermittedProviderType opt = configOptions.permittedProviderTypes(); - if (PermittedProviderType.ALL == opt) { - return true; - } else if (PermittedProviderType.NONE == opt) { - return false; - } else { - return configOptions.permittedProviderNames().contains(typeName.name()); - } - } - - static ServiceInfoCriteria toServiceInfoCriteria(TypeName typeName) { - return ServiceInfoCriteria.builder() - .serviceTypeName(typeName) - .includeIntercepted(true) - .build(); - } - - static ServiceProvider toServiceProvider(TypeName typeName, - Services services) { - return services.lookupFirst(toServiceInfoCriteria(typeName), true).orElseThrow(); - } - - static boolean isProvider(TypeName typeName, - Services services) { - ServiceProvider sp = toServiceProvider(typeName, services); - return sp.isProvider(); - } - - static boolean isAllowListedProviderQualifierTypeName(ApplicationCreatorConfigOptions configOptions, - TypeName typeName, - Services services) { - Set permittedTypeNames = configOptions.permittedProviderQualifierTypeNames(); - if (permittedTypeNames.isEmpty()) { - return false; - } - - ServiceProvider sp = toServiceProvider(typeName, services); - Set spQualifierTypeNames = sp.serviceInfo().qualifiers().stream() - .map(Annotation::typeName) - .collect(Collectors.toSet()); - spQualifierTypeNames.retainAll(permittedTypeNames); - return !spQualifierTypeNames.isEmpty(); - } - - /** - * Will uppercase the first letter of the provided name. - * - * @param name the name - * @return the mame with the first letter capitalized - */ - public static String upperFirstChar(String name) { - if (name.isEmpty()) { - return name; - } - return name.substring(0, 1).toUpperCase() + name.substring(1); - } - - static TypeName toApplicationTypeName(ApplicationCreatorRequest req) { - ApplicationCreatorCodeGen codeGen = Objects.requireNonNull(req.codeGen()); - String packageName = codeGen.packageName().orElse(null); - if (packageName == null) { - packageName = "inject"; - } - String className = Objects.requireNonNull(codeGen.className().orElse(null)); - return TypeName.builder() - .packageName(packageName) - .className(className) - .build(); - } - - static String toModuleName(ApplicationCreatorRequest req) { - return req.moduleName().orElse(ModuleInfoDescriptor.DEFAULT_MODULE_NAME); - } - - static Optional moduleServiceTypeOf(InjectionServices injectionServices, - String moduleName) { - Services services = injectionServices.services(); - ServiceProvider serviceProvider; - try { - serviceProvider = services.lookup(ModuleComponent.class, moduleName); - } catch (InjectionException e) { - return Optional.empty(); - } - return Optional.of(serviceProvider.serviceInfo().serviceTypeName()); - } - - /** - * Generates the source and class file for {@link Application} using the current classpath. - * - * @param req the request - * @return the response for application creation - */ - @Override - public ApplicationCreatorResponse createApplication(ApplicationCreatorRequest req) { - ApplicationCreatorResponse.Builder builder = ApplicationCreatorResponse.builder(); - - if (req.serviceTypeNames() == null) { - return handleError(req, new ToolsException("ServiceTypeNames is required to be passed"), builder); - } - - if (req.codeGen() == null) { - return handleError(req, new ToolsException("CodeGenPaths are required"), builder); - } - - List providersInUseThatAreAllowed = providersNotAllowed(req); - if (!providersInUseThatAreAllowed.isEmpty()) { - return handleError(req, - new ToolsException("There are dynamic " + Provider.class.getSimpleName() - + "s being used that are not allow-listed: " - + providersInUseThatAreAllowed - + "; see the documentation for examples of allow-listing."), builder); - } - - try { - return codegen(req, builder); - } catch (ToolsException te) { - return handleError(req, te, builder); - } catch (RuntimeException e) { - throw e; - } catch (Throwable t) { - return handleError(req, new ToolsException("Failed during create", t), builder); - } - } - - @SuppressWarnings("rawtypes") - List providersNotAllowed(ApplicationCreatorRequest req) { - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - Services services = injectionServices.services(); - - List> providers = services.lookupAll(Provider.class); - if (providers.isEmpty()) { - return List.of(); - } - - List providersInUseThatAreNotAllowed = new ArrayList<>(); - for (TypeName typeName : req.serviceTypeNames()) { - if (!isAllowListedProviderName(req.configOptions(), typeName) - && isProvider(typeName, services) - && !isAllowListedProviderQualifierTypeName(req.configOptions(), typeName, services)) { - providersInUseThatAreNotAllowed.add(typeName); - } - } - return providersInUseThatAreNotAllowed; - } - - ApplicationCreatorResponse codegen(ApplicationCreatorRequest req, - ApplicationCreatorResponse.Builder builder) { - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - - String serviceTypeBindingTemplate = templateHelper() - .safeLoadTemplate(req.templateName(), SERVICE_PROVIDER_APPLICATION_SERVICETYPEBINDING_HBS); - String serviceTypeBindingEmptyTemplate = templateHelper() - .safeLoadTemplate(req.templateName(), SERVICE_PROVIDER_APPLICATION_EMPTY_SERVICETYPEBINDING_HBS); - - List serviceTypeNames = new ArrayList<>(); - List serviceTypeBindings = new ArrayList<>(); - for (TypeName serviceTypeName : req.serviceTypeNames()) { - try { - String injectionPlan = toServiceTypeInjectionPlan(injectionServices, serviceTypeName, - serviceTypeBindingTemplate, serviceTypeBindingEmptyTemplate); - if (injectionPlan == null) { - continue; - } - serviceTypeNames.add(serviceTypeName); - serviceTypeBindings.add(injectionPlan); - } catch (Exception e) { - throw new ToolsException("Error during injection plan generation for: " + serviceTypeName, e); - } - } - - TypeName application = toApplicationTypeName(req); - serviceTypeNames.add(application); - - String moduleName = toModuleName(req); - - Map subst = new HashMap<>(); - subst.put("classname", application.className()); - subst.put("packagename", application.packageName()); - subst.put("description", application + " - Generated Application."); - subst.put("header", CopyrightHandler.copyright(CREATOR, - CREATOR, - application)); - subst.put("generatedanno", toGeneratedSticker(CREATOR, - CREATOR, // there is no specific type trigger for application - application)); - subst.put("modulename", moduleName); - subst.put("servicetypebindings", serviceTypeBindings); - - String template = templateHelper().safeLoadTemplate(req.templateName(), SERVICE_PROVIDER_APPLICATION_HBS); - String body = templateHelper().applySubstitutions(template, subst, true).trim(); - - if (req.codeGenPaths().isPresent() - && req.codeGenPaths().get().generatedSourcesPath().isPresent()) { - codegen(injectionServices, req, application, body); - } - - GeneralCodeGenDetail codeGenDetail = GeneralCodeGenDetail.builder() - .serviceTypeName(application) - .body(body) - .build(); - ApplicationCreatorCodeGen codeGenResponse = ApplicationCreatorCodeGen.builder() - .packageName(application.packageName()) - .className(application.className()) - .classPrefixName(req.codeGen().classPrefixName()) - .build(); - return builder - .applicationCodeGen(codeGenResponse) - .serviceTypeNames(serviceTypeNames) - .putServiceTypeDetail(application, codeGenDetail) - .templateName(req.templateName()) - .moduleName(req.moduleName()) - .build(); - } - - String toServiceTypeInjectionPlan(InjectionServices injectionServices, - TypeName serviceTypeName, - String serviceTypeBindingTemplate, - String serviceTypeBindingEmptyTemplate) { - Services services = injectionServices.services(); - - ServiceInfoCriteria si = toServiceInfoCriteria(serviceTypeName); - ServiceProvider sp = services.lookupFirst(si); - String activator = toActivatorCodeGen(sp); - if (activator == null) { - return null; - } - Map subst = new HashMap<>(); - subst.put("servicetypename", serviceTypeName.name()); - subst.put("activator", activator); - subst.put("modulename", sp.serviceInfo().moduleName().orElse(null)); - if (isQualifiedInjectionTarget(sp)) { - subst.put("injectionplan", toInjectionPlanBindings(sp)); - return templateHelper().applySubstitutions(serviceTypeBindingTemplate, subst, true); - } else { - return templateHelper().applySubstitutions(serviceTypeBindingEmptyTemplate, subst, true); - } - } - - @SuppressWarnings("unchecked") - List toInjectionPlanBindings(ServiceProvider sp) { - AbstractServiceProvider asp = AbstractServiceProvider - .toAbstractServiceProvider(ServiceBinderDefault.toRootProvider(sp), true).orElseThrow(); - DependenciesInfo deps = asp.dependencies(); - if (deps.allDependencies().isEmpty()) { - return List.of(); - } - - List plan = new ArrayList<>(deps.allDependencies().size()); - Map injectionPlan = asp.getOrCreateInjectionPlan(false); - for (Map.Entry e : injectionPlan.entrySet()) { - StringBuilder line = new StringBuilder(); - InjectionPointInfo ipInfo = e.getValue().injectionPointInfo(); - List> ipQualified = e.getValue().injectionPointQualifiedServiceProviders(); - List ipUnqualified = e.getValue().unqualifiedProviders(); - boolean resolved = false; - try { - if (ipInfo.listWrapped()) { - line.append(".bindMany("); - } else if (ipQualified.isEmpty()) { - if (!ipUnqualified.isEmpty()) { - resolved = true; - line.append(".resolvedBind("); - } else { - line.append(".bindVoid("); - } - } else { - line.append(".bind("); - } - - line.append("\"").append(e.getKey()).append("\""); - - if (resolved) { - Object target = ipUnqualified.get(0); - if (!(target instanceof Class)) { - target = target.getClass(); - } - line.append(", ").append(((Class) target).getName()).append(".class"); - } else if (ipInfo.listWrapped() && !ipQualified.isEmpty()) { - line.append(", ").append(toActivatorCodeGen((Collection>) ipQualified)); - } else if (!ipQualified.isEmpty()) { - line.append(", ").append(toActivatorCodeGen(ipQualified.get(0))); - } - line.append(")"); - - plan.add(line.toString()); - } catch (Exception exc) { - throw new IllegalStateException("Failed to process: " + e.getKey() + " with " + e.getValue(), exc); - } - } - - return plan; - } - - /** - * Perform the file creation and javac it. - * - * @param injectionServices the injection services to use - * @param req the request - * @param applicationTypeName the application type name - * @param body the source code / body to generate - */ - void codegen(InjectionServices injectionServices, - ApplicationCreatorRequest req, - TypeName applicationTypeName, - String body) { - CodeGenFiler filer = createDirectCodeGenFiler(req.codeGenPaths().orElse(null), req.analysisOnly()); - Path applicationJavaFilePath = filer.codegenJavaFilerOut(applicationTypeName, body).orElse(null); - - String outputDirectory = req.codeGenPaths().isEmpty() - ? null : req.codeGenPaths().get().outputPath().orElse(null); - if (outputDirectory != null) { - File outDir = new File(outputDirectory); - - // setup meta-inf services - codegenMetaInfServices(filer, - req.codeGenPaths().orElse(null), - Map.of(TypeNames.INJECT_APPLICATION, List.of(applicationTypeName.name()))); - - // setup module-info - codegenModuleInfoDescriptor(filer, injectionServices, req, applicationTypeName); - - // compile, but only if we generated the source file - if (applicationJavaFilePath != null) { - CompilerOptions opts = req.compilerOptions().orElse(null); - JavaC.Builder compilerBuilder = JavaC.builder() - .outputDirectory(outDir) - .logger(logger()) - .messager(req.messager().orElseThrow()); - if (opts != null) { - compilerBuilder - .classpath(opts.classpath()) - .modulepath(opts.modulepath()) - .sourcepath(opts.sourcepath()) - .source(opts.source()) - .target(opts.target()) - .commandLineArgs(opts.commandLineArguments()); - } - JavaC compiler = compilerBuilder.build(); - JavaC.Result result = compiler.compile(applicationJavaFilePath.toFile()); - ToolsException e = result.maybeGenerateError(); - if (e != null) { - throw new ToolsException("Failed to compile: " + applicationJavaFilePath, e); - } - } - } - } - - void codegenModuleInfoDescriptor(CodeGenFiler filer, - InjectionServices injectionServices, - ApplicationCreatorRequest req, - TypeName applicationTypeName) { - Optional injectionModuleInfoPath = filer.toResourceLocation(ModuleUtils.MODULE_INFO_JAVA_NAME); - ModuleInfoDescriptor descriptor = filer.readModuleInfo(ModuleUtils.MODULE_INFO_JAVA_NAME).orElse(null); - if (descriptor != null) { - Objects.requireNonNull(injectionModuleInfoPath.orElseThrow()); - String moduleName = req.moduleName().orElse(null); - if (moduleName == null || ModuleInfoDescriptor.DEFAULT_MODULE_NAME.equals(moduleName)) { - moduleName = descriptor.name(); - } - - TypeName moduleTypeName = moduleServiceTypeOf(injectionServices, moduleName).orElse(null); - if (moduleTypeName != null) { - String typePrefix = req.codeGen().classPrefixName(); - ModuleInfoCreatorRequest moduleBuilderRequest = ModuleInfoCreatorRequest.builder() - .name(moduleName) - .moduleTypeName(moduleTypeName) - .applicationTypeName(applicationTypeName) - .moduleInfoPath(injectionModuleInfoPath.get().toAbsolutePath().toString()) - .classPrefixName(typePrefix) - .applicationCreated(true) - .moduleCreated(false) - .build(); - descriptor = createModuleInfo(moduleBuilderRequest); - filer.codegenModuleInfoFilerOut(descriptor, true); - return; - } - } - - Path realModuleInfoPath = filer.toSourceLocation(ModuleUtils.REAL_MODULE_INFO_JAVA_NAME).orElse(null); - if (realModuleInfoPath != null && !realModuleInfoPath.toFile().exists()) { - throw new ToolsException("Expected to find " + realModuleInfoPath - + ". Did the Injection APT run?"); - } - } - - void codegenMetaInfServices(CodeGenFiler filer, - CodeGenPaths paths, - Map> metaInfServices) { - filer.codegenMetaInfServices(paths, metaInfServices); - } - - ApplicationCreatorResponse handleError(ApplicationCreatorRequest request, - ToolsException e, - ApplicationCreatorResponse.Builder builder) { - if (request.throwIfError()) { - throw e; - } - - return builder.error(e).success(false).build(); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorRequestBlueprint.java deleted file mode 100644 index d32b647bb1b..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorRequestBlueprint.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; - -/** - * Defines the request that will be passed to the {@link io.helidon.inject.tools.spi.ApplicationCreator} in order to produce the - * codegen artifacts. - */ -@Prototype.Blueprint -interface ApplicationCreatorRequestBlueprint extends GeneralCreatorRequestBlueprint { - - /** - * Mandatory, qualifies what specifically should be generated. - * - * @return data specific requests for what is generated - */ - ApplicationCreatorCodeGen codeGen(); - - /** - * Optionally, the config options and directives that applies to the request. - * - * @return configuration options and directives - */ - ApplicationCreatorConfigOptions configOptions(); - - /** - * Optionally, the messager to use. - * - * @return messager - */ - Optional messager(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorResponseBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorResponseBlueprint.java deleted file mode 100644 index df363afe277..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ApplicationCreatorResponseBlueprint.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.builder.api.Prototype; - -/** - * Response from {@link io.helidon.inject.tools.spi.ApplicationCreator}. - * - * @see io.helidon.inject.tools.spi.ApplicationCreator - */ -@Prototype.Blueprint -interface ApplicationCreatorResponseBlueprint extends GeneralCreatorResponseBlueprint { - - /** - * The basic description for the {@link io.helidon.inject.api.Application} generated. - * - * @return describes the application generated (package and class) - */ - ApplicationCreatorCodeGen applicationCodeGen(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenFiler.java b/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenFiler.java deleted file mode 100644 index d7451576208..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenFiler.java +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.FilerException; -import javax.tools.FileObject; -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.ModuleComponent; - -/** - * This class is used to generate the source and resources originating from either annotation processing or maven-plugin - * invocation. It also provides a circuit breaker in case the filer should be disabled from actually writing out source - * and resources, and instead will use the filer's messager to report what it would have performed (applicable for apt cases). - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class CodeGenFiler { - private static final boolean FORCE_MODULE_INFO_INTO_SCRATCH_DIR = true; - private static final boolean FILER_WRITE_ONCE_PER_TYPE = true; - private static final Set FILER_TYPES_FILED = new LinkedHashSet<>(); - private static volatile boolean filerWriteEnabled = true; - - private final AbstractFilerMessager filer; - private final Boolean enabled; - private final Path targetClassOutputPath; - private final Path scratchBaseOutputPath; - private final Path scratchClassClassOutputPath; - - /** - * Constructor. - * - * @param filer the filer to use for creating resources - */ - CodeGenFiler(AbstractFilerMessager filer) { - this(filer, null); - } - - /** - * Constructor. - * - * @param filer the filer to use for creating resources - * @param enabled true if forcing enablement, false if forcing disablement, null for using defaults - */ - CodeGenFiler(AbstractFilerMessager filer, - Boolean enabled) { - this.filer = Objects.requireNonNull(filer); - this.enabled = enabled; - this.targetClassOutputPath = targetClassOutputPath(filer); - this.scratchClassClassOutputPath = scratchClassOutputPath(targetClassOutputPath); - this.scratchBaseOutputPath = scratchClassClassOutputPath.getParent(); - } - - /** - * Creates a new code gen filer. - * - * @param filer the physical filer - * @return a newly created code gen filer - */ - public static CodeGenFiler create(AbstractFilerMessager filer) { - return new CodeGenFiler(filer); - } - - /** - * Provides the ability to disable actual file writing (convenient for unit testing). The default is true for - * enabled. - * - * @param enabled if disabled, pass false - * @return the previous value of this setting - */ - static boolean filerWriterEnabled(boolean enabled) { - boolean prev = filerWriteEnabled; - filerWriteEnabled = enabled; - return prev; - } - - /** - * Returns the path to the target scratch directory for Injection. - * - * @param targetOutputPath the target class output path - * @return the target scratch path - */ - public static Path scratchClassOutputPath(Path targetOutputPath) { - Path fileName = targetOutputPath.getFileName(); - Path parent = targetOutputPath.getParent(); - if (fileName == null || parent == null) { - throw new IllegalStateException(targetOutputPath.toString()); - } - String name = fileName.toString(); - return parent.resolve("inject").resolve(name); - } - - /** - * Returns the target class output directory. - * - * @param filer the filer - * @return the path to the target class output directory - */ - public static Path targetClassOutputPath(Filer filer) { - if (filer instanceof AbstractFilerMessager.DirectFilerMessager) { - CodeGenPaths paths = ((AbstractFilerMessager.DirectFilerMessager) filer).codeGenPaths(); - return Path.of(paths.outputPath().orElseThrow()); - } - - try { - FileObject f = filer.getResource(StandardLocation.CLASS_OUTPUT, "", "___"); - Path path = Path.of(f.toUri()); - if (path.getParent() == null) { - throw new IllegalStateException(path.toString()); - } - return path.getParent(); - } catch (Exception e) { - throw new ToolsException("Unable to determine output path", e); - } - } - - @Override - public String toString() { - return getClass().getSimpleName() + "(outputPath=" + targetClassOutputPath + ")"; - } - - boolean filerWriterEnabled() { - return (enabled != null) ? enabled : filerWriteEnabled; - } - - AbstractFilerMessager filer() { - return filer; - } - - Messager messager() { - return filer; - } - - /** - * Generate the meta-inf services given the provided map. - * - * @param paths paths to where code should be written - * @param metaInfServices the meta-inf services mapping - */ - public void codegenMetaInfServices(CodeGenPaths paths, - Map> metaInfServices) { - if (metaInfServices == null || metaInfServices.isEmpty()) { - return; - } - - Filer filer = filer(); - Messager messager = messager(); - Map> mergedMap = new LinkedHashMap<>(); - // load up any existing values, since this compilation may be partial and be run again... - for (Map.Entry> e : metaInfServices.entrySet()) { - String contract = e.getKey(); - Set mergedSet = new LinkedHashSet<>(e.getValue()); - mergedMap.put(contract, mergedSet); - String outPath = new File(paths.metaInfServicesPath() - .orElse(CodeGenPaths.DEFAULT_META_INF_SERVICES_PATH), contract).getPath(); - try { - messager.debug("Reading " + outPath); - FileObject f = filer.getResource(StandardLocation.CLASS_OUTPUT, "", outPath); - try (InputStream is = f.openInputStream(); - BufferedReader r = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { - String line; - while ((line = r.readLine()) != null) { - mergedSet.add(line); - } - } - } catch (FilerException | NoSuchFileException | FileNotFoundException x) { - // don't show the exception in this case - messager.debug(getClass().getSimpleName() + ":" + x.getMessage()); - } catch (Exception x) { - ToolsException te = - new ToolsException("Failed to find/load existing META-INF/services file: " + x.getMessage(), x); - messager.warn(te.getMessage(), te); - } - } - - for (Map.Entry> e : mergedMap.entrySet()) { - String contract = e.getKey(); - String outPath = new File(paths.metaInfServicesPath().orElseThrow(), contract).getPath(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos, StandardCharsets.UTF_8))) { - for (String value : e.getValue()) { - pw.println(value); - } - } - - codegenResourceFilerOut(outPath, baos.toString(StandardCharsets.UTF_8)); - } - } - - /** - * Code generates a resource. - * - * @param outPath the path to output the resource to - * @param body the resource body - * @return file path coordinates corresponding to the resource in question, or empty if not generated - */ - public Optional codegenResourceFilerOut(String outPath, - String body) { - return codegenResourceFilerOut(outPath, body, Optional.empty()); - } - - /** - * Code generates a resource, providing the ability to update the body if the resource already exists. - * - * @param outPath the path to output the resource to - * @param body the resource body - * @param updater the updater of the body - * @return file path coordinates corresponding to the resource in question, or empty if not generated - */ - Optional codegenResourceFilerOut(String outPath, - String body, - Function updater) { - return codegenResourceFilerOut(outPath, body, Optional.of(updater)); - } - - /** - * Code generates the {@link ModuleComponent} source. - * - * @param moduleDetail the module details - */ - void codegenModuleFilerOut(ModuleDetail moduleDetail) { - if (moduleDetail.moduleBody().isEmpty()) { - return; - } - - TypeName typeName = moduleDetail.moduleTypeName(); - String body = moduleDetail.moduleBody().orElseThrow(); - codegenJavaFilerOut(typeName, body); - } - - /** - * Code generates the {@link Application} source. - * - * @param applicationTypeName the application type - * @param body the application body of source - */ - void codegenApplicationFilerOut(TypeName applicationTypeName, - String body) { - codegenJavaFilerOut(applicationTypeName, body); - } - - /** - * Code generates the {@link Activator} source. - * - * @param activatorDetail the activator details - */ - void codegenActivatorFilerOut(ActivatorCodeGenDetail activatorDetail) { - if (activatorDetail.body().isEmpty()) { - return; - } - - TypeName typeName = activatorDetail.serviceTypeName(); - String body = activatorDetail.body().orElseThrow(); - codegenJavaFilerOut(typeName, body); - } - - /** - * Code generate a java source file. - * - * @param typeName the source type name - * @param body the source body - * @return the new file path coordinates or empty if nothing was written - */ - public Optional codegenJavaFilerOut(TypeName typeName, - String body) { - Messager messager = messager(); - if (!filerWriterEnabled()) { - messager.log("(disabled) Writing " + typeName + " with:\n" + body); - return Optional.empty(); - } - - if (FILER_WRITE_ONCE_PER_TYPE && !FILER_TYPES_FILED.add(typeName)) { - ToolsException te = new ToolsException("Attempt to reprocess: " + typeName); - messager.error(te.getMessage(), te); - } - - messager.debug("Writing " + typeName); - - Filer filer = filer(); - try { - JavaFileObject javaSrc = filer.createSourceFile(typeName.name()); - try (Writer os = javaSrc.openWriter()) { - os.write(body); - } - return Optional.of(Path.of(javaSrc.toUri())); - } catch (Exception x) { - ToolsException te = new ToolsException("Failed to write java file: " + typeName, x); - messager.error(te.getMessage(), te); - throw te; - } - } - - /** - * Code generate the {@code module-info.java.inject} file. - * - * @param newDeltaDescriptor the descriptor - * @param overwriteTargetIfExists should the file be overwritten if it already exists - * @return the module-info coordinates, or empty if nothing was written - */ - Optional codegenModuleInfoFilerOut(ModuleInfoDescriptor newDeltaDescriptor, - boolean overwriteTargetIfExists) { - Objects.requireNonNull(newDeltaDescriptor); - - Messager messager = messager(); - String typeName = ModuleUtils.MODULE_INFO_JAVA_NAME; - if (!filerWriterEnabled()) { - messager.log("(disabled) Writing " + typeName + " with:\n" + newDeltaDescriptor); - return Optional.empty(); - } - messager.debug("Writing " + typeName); - - Function moduleInfoUpdater = inputStream -> { - ModuleInfoDescriptor existingDescriptor = ModuleInfoDescriptor.create(inputStream); - ModuleInfoDescriptor newDescriptor = existingDescriptor.mergeCreate(newDeltaDescriptor); - return newDescriptor.contents(); - }; - - Optional filePath - = codegenResourceFilerOut(typeName, newDeltaDescriptor.contents(), moduleInfoUpdater); - if (filePath.isPresent()) { - messager.debug("Wrote module-info: " + filePath.get()); - } else if (overwriteTargetIfExists) { - messager.warn("Expected to have written module-info, but failed to write it"); - } - - if (!newDeltaDescriptor.isUnnamed()) { - ModuleUtils.saveAppPackageName(scratchBaseOutputPath, - ModuleUtils.normalizedBaseModuleName(newDeltaDescriptor.name())); - } - - return filePath; - } - - /** - * Reads in the module-info if it exists, or returns null if it doesn't exist. - * - * @param name the name to the module-info file - * @return the module-info descriptor, or empty if it doesn't exist - */ - Optional readModuleInfo(String name) { - try { - CharSequence body = readResourceAsString(name); - return Optional.ofNullable((body == null) ? null : ModuleInfoDescriptor.create(body.toString())); - } catch (Exception e) { - throw new ToolsException("Failed to read module-info: " + name, e); - } - } - - /** - * Reads in a resource from the {@link javax.tools.StandardLocation#CLASS_OUTPUT} location. - * - * @param name the name of the resource - * @return the body of the resource as a string, or null if it doesn't exist - */ - CharSequence readResourceAsString(String name) { - try { - FileObject f = filer.getResource(StandardLocation.CLASS_OUTPUT, "", name); - return f.getCharContent(true); - } catch (IOException e) { - if (FORCE_MODULE_INFO_INTO_SCRATCH_DIR - && targetClassOutputPath != null - && name.equals(ModuleUtils.MODULE_INFO_JAVA_NAME)) { - // hack: physically read it from its relocated location - File newPath = new File(scratchClassClassOutputPath.toFile(), name); - if (newPath.exists()) { - try { - return Files.readString(newPath.toPath()); - } catch (IOException e2) { - throw new ToolsException(e2.getMessage(), e2); - } - } - } - - messager().debug("Unable to load resource: " + name); - return null; - } - } - - /** - * Attempts to translate the resource name to a file coordinate, or null if translation is not possible. - * - * @param name the name of the resource - * @return the file path coordinates if it can be ascertained, or empty if not possible to ascertain this information - */ - Optional toResourceLocation(String name) { - // hack: physically read it from its relocated location - if (FORCE_MODULE_INFO_INTO_SCRATCH_DIR - && targetClassOutputPath != null - && name.equals(ModuleUtils.MODULE_INFO_JAVA_NAME)) { - return Optional.of(scratchClassClassOutputPath.resolve(name)); - } - - try { - FileObject f = filer.getResource(StandardLocation.CLASS_OUTPUT, "", name); - Path path = Paths.get(f.toUri()); - return Optional.of(path); - } catch (IOException e) { - messager().debug("unable to load resource: " + name); - } - - return Optional.empty(); - } - - /** - * Attempts to translate the type name to a file coordinate, or empty if translation is not possible. - * - * @param name the name of the type - * @return the file coordinates if it can be ascertained, or empty if not possible to ascertain this information - * - * @see ModuleUtils#toSourcePath for annotation processing use cases - */ - Optional toSourceLocation(String name) { - if (filer instanceof AbstractFilerMessager.DirectFilerMessager) { - TypeName typeName = TypeName.create(name); - Optional path = Optional.ofNullable(((AbstractFilerMessager.DirectFilerMessager) filer) - .toSourcePath(StandardLocation.SOURCE_PATH, typeName)); - if (path.isPresent()) { - return path; - } - } - - messager().log(CodeGenFiler.class.getSimpleName() + ": unable to determine source location for: " + name); - return Optional.empty(); - } - - private Filer scratchFiler() throws IOException { - Files.createDirectories(scratchClassClassOutputPath); - CodeGenPaths codeGenPaths = CodeGenPaths.builder() - .outputPath(scratchClassClassOutputPath.toString()) - .build(); - return new AbstractFilerMessager.DirectFilerMessager(codeGenPaths, filer.logger()); - } - - private Optional codegenResourceFilerOut(String outPath, - String body, - Optional> optFnUpdater) { - Messager messager = messager(); - if (!filerWriterEnabled()) { - messager.log("(disabled) Writing " + outPath + " with:\n" + body); - return Optional.empty(); - } - messager.debug("Writing " + outPath); - - Filer filer = filer(); - Function fnUpdater = optFnUpdater.orElse(null); - - try { - if (FORCE_MODULE_INFO_INTO_SCRATCH_DIR - && targetClassOutputPath != null - && outPath.equals(ModuleUtils.MODULE_INFO_JAVA_NAME)) { - // hack: physically relocate it elsewhere under our scratch output directory - filer = scratchFiler(); - } - - FileObject f = filer.getResource(StandardLocation.CLASS_OUTPUT, "", outPath); - Path fPath = Path.of(f.toUri()); - if (fPath.toFile().exists()) { - if (fnUpdater != null) { - // update it... - try (InputStream is = f.openInputStream()) { - body = fnUpdater.apply(is); - } - } - - String actualContents = Files.readString(fPath, StandardCharsets.UTF_8); - if (!actualContents.equals(body)) { - Files.writeString(fPath, body, StandardCharsets.UTF_8); - } - } else { - // file does not exist yet... create it the normal way - f = filer.createResource(StandardLocation.CLASS_OUTPUT, "", outPath); - try (Writer os = f.openWriter()) { - os.write(body); - } - fPath = Path.of(f.toUri()); - } - - return Optional.of(fPath); - } catch (Exception x) { - ToolsException te = new ToolsException("Error writing resource file: " + x.getMessage(), x); - messager.error(te.getMessage(), te); - // should not make it here - throw te; - } - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenInterceptorRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenInterceptorRequestBlueprint.java deleted file mode 100644 index 623a2d62198..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenInterceptorRequestBlueprint.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Map; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * Used by {@link io.helidon.inject.tools.spi.ActivatorCreator#codegenInterceptors}. - */ -@Prototype.Blueprint -interface CodeGenInterceptorRequestBlueprint { - - /** - * The general creator request. - * - * @return the general creator request - */ - GeneralCreatorRequest generalCreatorRequest(); - - /** - * The interception plan. - * - * @return the interception plan - */ - Map interceptionPlans(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenPathsBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenPathsBlueprint.java deleted file mode 100644 index 0e3226c46f5..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenPathsBlueprint.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Applies only to the output paths that various {@code creators} will use (e.g., - * {@link io.helidon.inject.tools.spi.ActivatorCreator}). - */ -@Prototype.Blueprint -interface CodeGenPathsBlueprint { - - /** - * The default path for {@link #metaInfServicesPath()}. - * - */ - String DEFAULT_META_INF_SERVICES_PATH = "META-INF/services"; - - /** - * Identifies where the meta-inf services should be written. - * - * @return where should meta-inf services be written - */ - @ConfiguredOption(DEFAULT_META_INF_SERVICES_PATH) - Optional metaInfServicesPath(); - - /** - * Identifies where is the source directory resides. - * - * @return the source directory - */ - Optional sourcePath(); - - /** - * Identifies where the generated sources should be written. - * - * @return where should the generated sources be written - */ - Optional generatedSourcesPath(); - - /** - * Identifies where the classes directory resides. - * - * @return the classes directory - */ - Optional outputPath(); - - /** - * Identifies where the module-info can be found. - * - * @return the module-info location - */ - Optional moduleInfoPath(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenUtils.java b/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenUtils.java deleted file mode 100644 index 0427b9a1b64..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CodeGenUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.inject.api.ElementInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.InjectionPointInfo; - -/** - * Code generation utilities. - */ -final class CodeGenUtils { - - private CodeGenUtils() { - } - - static String elementNameKindRef(String elemName, - ElementKind elemKind) { - if (elemKind == ElementKind.CONSTRUCTOR - && elemName.equals(InjectionPointInfo.CONSTRUCTOR)) { - elemName = "CONSTRUCTOR"; - } else { - elemName = "\"" + elemName + "\""; - } - return elemName; - } - - static String elementNameRef(String elemName) { - if (elemName.equals(ElementInfo.CONSTRUCTOR)) { - return ElementInfo.class.getName() + "." + "CONSTRUCTOR"; - } - return "\"" + elemName + "\""; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CommonUtils.java b/inject/tools/src/main/java/io/helidon/inject/tools/CommonUtils.java deleted file mode 100644 index f9775fb5d5d..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CommonUtils.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * General utils. - */ -final class CommonUtils { - - private CommonUtils() { - } - - /** - * Loads a string from a resource using this loader that loaded this class. - * - * @param resourceNamePath the resource path - * @return the loaded string resource - * @throws ToolsException if there were any exceptions encountered - */ - static String loadStringFromResource(String resourceNamePath) { - try { - try (InputStream in = CommonUtils.class.getClassLoader().getResourceAsStream(resourceNamePath)) { - return new String(in.readAllBytes(), StandardCharsets.UTF_8); - } - } catch (Exception e) { - throw new ToolsException("Failed to load: " + resourceNamePath, e); - } - } - - /** - * Loads a String from a file, wrapping any exception encountered to a {@link ToolsException}. - * - * @param fileName the file name to load - * @return the contents of the file - * @throws ToolsException if there were any exceptions encountered - */ - static String loadStringFromFile(String fileName) { - try { - Path filePath = Path.of(fileName); - String content = Files.readString(filePath); - return content; - } catch (IOException e) { - throw new ToolsException("Unable to load from file: " + fileName, e); - } - } - - /** - * Converts a collection using a {@code path.separator} delimited string. - * - * @param coll the collection - * @return the concatenated, delimited string value - */ - static String toPathString(Collection coll) { - return toString(coll, null, System.getProperty("path.separator")); - } - - /** - * Converts a collection to a comma delimited string. - * - * @param coll the collection - * @return the concatenated, delimited string value - */ - static String toString(Collection coll) { - return toString(coll, null, null); - } - - /** - * Provides specialization in concatenation, allowing for a function to be called for each element as well as to - * use special separators. - * - * @param coll the collection - * @param fnc the optional function to translate the collection item to a string - * @param separator the optional separator - * @param the type held by the collection - * @return the concatenated, delimited string value - */ - static String toString(Collection coll, - Function fnc, - String separator) { - Function fn = (fnc == null) ? String::valueOf : fnc; - separator = (separator == null) ? ", " : separator; - return coll.stream().map(fn::apply).collect(Collectors.joining(separator)); - } - - /** - * Splits given using a comma-delimiter, and returns a trimmed list of string for each item. - * - * @param str the string to split - * @return the list of string values - */ - static List toList(String str) { - return toList(str, ","); - } - - /** - * Splits a string given a delimiter, and returns a trimmed list of string for each item. - * - * @param str the string to split - * @param delim the delimiter - * @return the list of string values - */ - static List toList(String str, - String delim) { - String[] split = str.split(delim); - return Arrays.stream(split).map(String::trim).collect(Collectors.toList()); - } - - /** - * Converts the collection of type T to a set of strings, handling the null case. - * - * @param coll the collection or null - * @param fn the mapper function - * @param the type of the items in the collection - * @return the set of mapped strings from the collection - */ - static Set toSet(Collection coll, - Function fn) { - if (coll == null) { - return Set.of(); - } - - return coll.stream().map(fn).collect(Collectors.toSet()); - } - - /** - * Trims each line of a multi-line string. - * - * @param multiLineStr the string - * @return the trimmed content - */ - static String trimLines(String multiLineStr) { - BufferedReader reader = new BufferedReader(new StringReader(multiLineStr)); - String line; - StringBuilder builder = new StringBuilder(); - try { - while (null != (line = reader.readLine())) { - if (line.isBlank()) { - builder.append("\n"); - } else { - builder.append(line.stripTrailing()).append("\n"); - } - } - } catch (IOException e) { - throw new ToolsException("failed to read", e); - } - return builder.toString().trim(); - } - - /** - * Returns the first element of a collection. - * - * @param coll the collection - * @param allowEmptyCollection if true, and the collection is empty, will return null instead of throwing - * @param the type of the collection - * @return the first element, or null if empty collections are allowed - * @throws ToolsException if not allowEmptyCollection and the collection is empty - */ - static T first(Collection coll, - boolean allowEmptyCollection) { - if (coll.isEmpty()) { - if (allowEmptyCollection) { - return null; - } else { - throw new ToolsException("Expected a non-empty collection"); - } - } - - return coll.iterator().next(); - } - - static boolean hasValue( - String str) { - return (str != null && !str.isBlank()); - } - - /** - * Replaces the provided string's usage of '.' with '$'. - * - * @param className the classname - * @return the converted string - */ - static String toFlatName(String className) { - return className.replace('.', '$'); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CompilerOptionsBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/CompilerOptionsBlueprint.java deleted file mode 100644 index 1ec53f0f9a2..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CompilerOptionsBlueprint.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.nio.file.Path; -import java.util.List; - -import io.helidon.builder.api.Prototype; - -/** - * Provides configuration to the javac compiler. - */ -@Prototype.Blueprint -interface CompilerOptionsBlueprint { - - /** - * The classpath to pass to the compiler. - * - * @return classpath - */ - List classpath(); - - /** - * The modulepath to pass to the compiler. - * - * @return the module path - */ - List modulepath(); - - /** - * The source path to pass to the compiler. - * - * @return the source path - */ - List sourcepath(); - - /** - * The command line arguments to pass to the compiler. - * - * @return arguments - */ - List commandLineArguments(); - - /** - * The compiler source version. - * - * @return source version - */ - String source(); - - /** - * The compiler target version. - * - * @return target version - */ - String target(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateRequestBlueprint.java deleted file mode 100644 index 3f5f93076c6..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateRequestBlueprint.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeInfo; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.inject.api.ServiceInfoBasics; - -/** - * The request will be generated internally and then passed to the appropriate - * {@link io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator} to handle the request. - */ -@Prototype.Blueprint -interface CustomAnnotationTemplateRequestBlueprint { - - /** - * The type of the annotation being processed. - * - * @return the type of the annotation being processed - */ - TypeName annoTypeName(); - - /** - * The target element being processed. This element is the one with the {@link #annoTypeName()} assigned to it. - * - * @return the target element being processed - */ - TypedElementInfo targetElement(); - - /** - * The access modifier of the element. - * - * @return the access modifier of the element - */ - AccessModifier targetElementAccess(); - - /** - * Only applicable for {@link javax.lang.model.element.ElementKind#METHOD} or - * {@link javax.lang.model.element.ElementKind#CONSTRUCTOR}. - * - * @return the list of typed arguments for this method or constructor - */ - List targetElementArgs(); - - /** - * Returns true if the element is declared to be static. - * - * @return returns true if the element is declared to be private - */ - @ConfiguredOption("false") - boolean isElementStatic(); - - /** - * Projects the {@link #enclosingTypeInfo()} as a {@link io.helidon.inject.api.ServiceInfoBasics} type. - * - * @return the basic service info of the element being processed - */ - ServiceInfoBasics serviceInfo(); - - /** - * The enclosing class type info of the target element being processed. - * - * @return the enclosing class type info of the target element being processed - */ - TypeInfo enclosingTypeInfo(); - - /** - * Returns true if the code should be literally generated with the provided {@code filer}. - * - * @return true if the code should be literally generated with the filer - */ - @ConfiguredOption("true") - boolean isFilerEnabled(); - - /** - * Generic template creator. - * - * @return the generic template creator - */ - GenericTemplateCreator genericTemplateCreator(); -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateResponseBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateResponseBlueprint.java deleted file mode 100644 index 267859a2cbd..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateResponseBlueprint.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Map; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; - -/** - * The response from {@link io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator#create(CustomAnnotationTemplateRequest)}. - */ -@Prototype.Blueprint -interface CustomAnnotationTemplateResponseBlueprint { - - /** - * The request that was processed. - * - * @return the request that was processed - */ - CustomAnnotationTemplateRequest request(); - - /** - * Any source that should be code generated. - * - * @return map of generated type name to body of the source to be generated - */ - @Option.Singular - Map generatedSourceCode(); - - /** - * Any generated resources should be generated. - * - * @return map of generated type name (which is really just a directory path under resources) to the resource to be generated - */ - @Option.Singular - Map generatedResources(); -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateResponses.java b/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateResponses.java deleted file mode 100644 index 307fade9a80..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/CustomAnnotationTemplateResponses.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -/** - * Custom annotation template response utility. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public final class CustomAnnotationTemplateResponses { - private CustomAnnotationTemplateResponses() { - } - - /** - * Aggregates the responses given to one response. - * - * @param request the request being processed - * @param responses the responses to aggregate into one response instance - * @return the aggregated response - */ - public static CustomAnnotationTemplateResponse.Builder aggregate(CustomAnnotationTemplateRequest request, - CustomAnnotationTemplateResponse... responses) { - CustomAnnotationTemplateResponse.Builder response = CustomAnnotationTemplateResponse.builder() - .request(request); - for (CustomAnnotationTemplateResponse res : responses) { - if (res == null) { - continue; - } - - response.addGeneratedSourceCode(res.generatedSourceCode()); - response.addGeneratedResources(res.generatedResources()); - } - return response; - } -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorDefault.java b/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorDefault.java deleted file mode 100644 index de7d922f67c..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorDefault.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.net.URI; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.LazyValue; -import io.helidon.common.Weight; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.runtime.Dependencies; -import io.helidon.inject.tools.spi.ExternalModuleCreator; - -import io.github.classgraph.ClassInfo; -import io.github.classgraph.ClassInfoList; -import io.github.classgraph.ClassMemberInfo; -import io.github.classgraph.FieldInfo; -import io.github.classgraph.MethodInfo; -import io.github.classgraph.MethodParameterInfo; -import io.github.classgraph.ModuleInfo; -import io.github.classgraph.PackageInfo; -import io.github.classgraph.ScanResult; -import jakarta.inject.Singleton; - -import static io.helidon.inject.api.ServiceInfoBasics.DEFAULT_INJECT_WEIGHT; -import static java.util.function.Predicate.not; - -/** - * The default implementation of {@link ExternalModuleCreator}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Singleton -@Weight(DEFAULT_INJECT_WEIGHT) -public class ExternalModuleCreatorDefault extends AbstractCreator implements ExternalModuleCreator { - private static final Set SERVICE_DEFINING_ANNOTATIONS = Set.of(TypeNames.JAKARTA_SINGLETON, - TypeNames.JAKARTA_APPLICATION_SCOPED); - private final LazyValue scan = LazyValue.create(ReflectionHandler.INSTANCE.scan()); - private final ServicesToProcess services = ServicesToProcess.servicesInstance(); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public ExternalModuleCreatorDefault() { - super(TemplateHelper.DEFAULT_TEMPLATE_NAME); - } - - static boolean isInjectionSupported(TypeName serviceTypeName, - MethodInfo methodInfo, - System.Logger logger) { - return InjectionSupported.isSupportedInjectionPoint(logger, serviceTypeName, methodInfo.toString(), - TypeTools.isPrivate(methodInfo.getModifiers()), methodInfo.isStatic()); - } - - @Override - public ExternalModuleCreatorResponse prepareToCreateExternalModule(ExternalModuleCreatorRequest req) { - Objects.requireNonNull(req); - - ExternalModuleCreatorResponse.Builder responseBuilder = - ExternalModuleCreatorResponse.builder(); - Collection packageNames = req.packageNamesToScan(); - if (packageNames.isEmpty()) { - return handleError(req, new ToolsException("Package names to scan are required"), responseBuilder); - } - - Collection targetExternalJars = identifyExternalJars(packageNames); - if (1 != targetExternalJars.size()) { - return handleError(req, new ToolsException("The package names provided " + packageNames - + " must map to a single jar file, but instead found: " - + targetExternalJars), responseBuilder); - } - - try { - // handle the explicit qualifiers passed in - req.serviceTypeToQualifiersMap().forEach((serviceTypeName, qualifiers) -> - services.addQualifiers(TypeName.create(serviceTypeName), - qualifiers)); - - // process each found service type - scan.get().getAllStandardClasses() - .stream() - .filter(classInfo -> packageNames.contains(classInfo.getPackageName())) - .filter(not(ClassInfo::isInterface)) - .filter(not(ClassInfo::isExternalClass)) - .filter(classInfo -> !TypeTools.isPrivate(classInfo.getModifiers())) - .filter(classInfo -> !classInfo.isInnerClass() || req.innerClassesProcessed()) - .forEach(this::processServiceType); - - ActivatorCreatorCodeGen activatorCreatorCodeGen = ActivatorCreatorDefault - .createActivatorCreatorCodeGen(services).orElseThrow(); - ActivatorCreatorRequest activatorCreatorRequest = ActivatorCreatorDefault - .createActivatorCreatorRequest(services, - activatorCreatorCodeGen, - req.activatorCreatorConfigOptions(), - req.filer(), - req.throwIfError()); - return responseBuilder - .activatorCreatorRequest(activatorCreatorRequest) - .serviceTypeNames(services.serviceTypeNames()) - .moduleName(services.moduleName()) - .packageName(activatorCreatorRequest.packageName()) - .build(); - } catch (Throwable t) { - return handleError(req, new ToolsException("failed to analyze / prepare external module", t), responseBuilder); - } finally { - services.reset(false); - } - } - - ExternalModuleCreatorResponse handleError(ExternalModuleCreatorRequest request, - ToolsException e, - ExternalModuleCreatorResponse.Builder builder) { - if (request == null || request.throwIfError()) { - throw e; - } - - logger().log(System.Logger.Level.ERROR, e.getMessage(), e); - - return builder.error(e).success(false).build(); - } - - private Collection identifyExternalJars(Collection packageNames) { - Set classpath = new LinkedHashSet<>(); - for (String packageName : packageNames) { - PackageInfo packageInfo = scan.get().getPackageInfo(packageName); - if (packageInfo != null) { - for (ClassInfo classInfo : packageInfo.getClassInfo()) { - URI uri = classInfo.getClasspathElementURI(); - classpath.add(Path.of(uri)); - } - } - } - return classpath; - } - - private void processServiceType(ClassInfo classInfo) { - logger().log(System.Logger.Level.DEBUG, "processing " + classInfo); - - TypeName serviceTypeName = TypeTools.createTypeNameFromClassInfo(classInfo); - - ModuleInfo moduleInfo = classInfo.getModuleInfo(); - Collection requiresModule = null; - if (moduleInfo != null) { - requiresModule = Collections.singleton(moduleInfo.getName()); - services.moduleName(moduleInfo.getName()); - } - - processTypeAndContracts(classInfo, serviceTypeName, requiresModule); - processScopeAndQualifiers(classInfo, serviceTypeName); - processPostConstructAndPreDestroy(classInfo, serviceTypeName); - processDependencies(classInfo, serviceTypeName); - } - - private void processTypeAndContracts(ClassInfo classInfo, - TypeName serviceTypeName, - Collection requiresModule) { - services.addServiceTypeName(serviceTypeName); - services.addTypeForContract(serviceTypeName, serviceTypeName, true); - services.addExternalRequiredModules(serviceTypeName, requiresModule); - ClassInfo superclass = classInfo.getSuperclass(); - if (superclass != null) { - handleSuperClass(serviceTypeName, superclass); - } - List hierarchy = ActivatorCreatorDefault.serviceTypeHierarchy(serviceTypeName, scan); - services.addServiceTypeHierarchy(serviceTypeName, hierarchy); - if (hierarchy != null) { - hierarchy.stream() - .filter((parentTypeName) -> !parentTypeName.equals(serviceTypeName)) - .forEach((parentTypeName) -> services.addTypeForContract(serviceTypeName, parentTypeName, false)); - } - services.addAccessLevel(serviceTypeName, TypeTools.toAccess(classInfo.getModifiers())); - services.addIsAbstract(serviceTypeName, TypeTools.isAbstract(classInfo.getModifiers())); - - boolean firstRound = true; - while (classInfo != null && !Object.class.getName().equals(classInfo.getName())) { - ClassInfoList list = classInfo.getInterfaces(); - for (ClassInfo contractClassInfo : list) { - String cn = contractClassInfo.getName(); - TypeName contract = TypeName.create(cn); - services.addTypeForContract(serviceTypeName, contract, true); - } - if (firstRound) { - String cn = TypeTools.providesContractType(classInfo); - if (cn != null) { - TypeName contract = TypeName.create(cn); - services.addTypeForContract(serviceTypeName, contract, true); - services.addProviderFor(serviceTypeName, Collections.singleton(contract)); - } - } - classInfo = classInfo.getSuperclass(); - firstRound = false; - } - } - - private void handleSuperClass(TypeName serviceTypeName, ClassInfo superclass) { - // looking for the closes type that is either a bean, or that has injection points (as that type MUST have an activator) - findActivatedInHierarchy(superclass, new HashSet<>()) - .ifPresent(it -> services.addParentServiceType(serviceTypeName, TypeName.builder(it.genericTypeName()) - .className(it.classNameWithEnclosingNames() - .replace('.', '$') + ActivatorCreatorDefault.INNER_ACTIVATOR_CLASS_NAME) - .build())); - } - - private Optional findActivatedInHierarchy(ClassInfo superClass, HashSet processed) { - if (!processed.add(superClass)) { - return Optional.empty(); - } - // any type that has - // - @Singleton on type (or any other "service defining annotation"), or has @Scope meta annotation - // - @Inject on any field or constructor - // same code in InjectionAnnotationProcessor for TypeInfo - for (ClassInfo annotation : superClass.getAnnotations()) { - if (SERVICE_DEFINING_ANNOTATIONS.contains(annotation.getName())) { - return Optional.of(TypeName.create(superClass.getName())); - } - } - for (FieldInfo field : superClass.getDeclaredFieldInfo()) { - if (hasInjectAnnotation(field)) { - return Optional.of(TypeName.create(superClass.getName())); - } - } - for (MethodInfo method : superClass.getDeclaredMethodAndConstructorInfo()) { - if (hasInjectAnnotation(method)) { - return Optional.of(TypeName.create(superClass.getName())); - } - } - return Optional.ofNullable(superClass.getSuperclass()) - .flatMap(it -> findActivatedInHierarchy(it, processed)); - } - - private boolean hasInjectAnnotation(ClassMemberInfo member) { - return member.hasAnnotation(TypeNames.JAKARTA_INJECT) || member.hasAnnotation(TypeNames.JAVAX_INJECT); - } - - private void processScopeAndQualifiers(ClassInfo classInfo, - TypeName serviceTypeName) { - TypeName scopeTypeName = TypeTools.extractScopeTypeName(classInfo); - if (scopeTypeName != null) { - services.addScopeTypeName(serviceTypeName, scopeTypeName); - } - - Set qualifiers = TypeTools.createQualifierSet(classInfo); - if (!qualifiers.isEmpty()) { - services.addQualifiers(serviceTypeName, qualifiers); - } - } - - private void processPostConstructAndPreDestroy(ClassInfo classInfo, - TypeName serviceTypeName) { - MethodInfo postConstructMethod = TypeTools.methodsAnnotatedWith(classInfo, TypeNames.JAKARTA_POST_CONSTRUCT) - .stream().findFirst().orElse(null); - if (postConstructMethod != null) { - services.addPostConstructMethod(serviceTypeName, postConstructMethod.getName()); - } - - MethodInfo preDestroyMethods = TypeTools.methodsAnnotatedWith(classInfo, TypeNames.JAKARTA_PRE_DESTROY) - .stream().findFirst().orElse(null); - if (preDestroyMethods != null) { - services.addPreDestroyMethod(serviceTypeName, preDestroyMethods.getName()); - } - } - - private void processDependencies(ClassInfo classInfo, - TypeName serviceTypeName) { - Dependencies.BuilderContinuation continuation = Dependencies.builder(serviceTypeName); - for (FieldInfo fieldInfo : classInfo.getFieldInfo()) { - continuation = continuationProcess(serviceTypeName, continuation, fieldInfo); - } - - for (MethodInfo ctorInfo : classInfo.getDeclaredConstructorInfo()) { - continuation = continuationProcess(serviceTypeName, - continuation, ElementKind.CONSTRUCTOR, ctorInfo); - } - - for (MethodInfo methodInfo : classInfo.getDeclaredMethodInfo()) { - continuation = continuationProcess(serviceTypeName, - continuation, ElementKind.METHOD, methodInfo); - } - - DependenciesInfo dependencies = continuation.build(); - services.addDependencies(dependencies); - } - - private Dependencies.BuilderContinuation continuationProcess(TypeName serviceTypeName, - Dependencies.BuilderContinuation continuation, - FieldInfo fieldInfo) { - if (TypeTools.hasAnnotation(fieldInfo, TypeNames.JAKARTA_INJECT)) { - if (!InjectionSupported.isSupportedInjectionPoint(logger(), - serviceTypeName, fieldInfo.toString(), - TypeTools.isPrivate(fieldInfo.getModifiers()), fieldInfo.isStatic())) { - return continuation; - } - - InjectionPointInfo ipInfo = TypeTools.createInjectionPointInfo(serviceTypeName, fieldInfo); - continuation = continuation.add(ipInfo); - } - - return continuation; - } - - private Dependencies.BuilderContinuation continuationProcess(TypeName serviceTypeName, - Dependencies.BuilderContinuation continuation, - ElementKind kind, - MethodInfo methodInfo) { - if (TypeTools.hasAnnotation(methodInfo, TypeNames.JAKARTA_INJECT)) { - if (!isInjectionSupported(serviceTypeName, methodInfo, logger())) { - return continuation; - } - - MethodParameterInfo[] params = methodInfo.getParameterInfo(); - if (params.length == 0) { - continuation = continuation.add(methodInfo.getName(), Void.class, kind, - TypeTools.toAccess(methodInfo.getModifiers())) - .ipName(methodInfo.getName()) - .ipType(TypeName.create(Void.class)) - .staticDeclaration(TypeTools.isStatic(methodInfo.getModifiers())); - } else { - int count = 0; - for (MethodParameterInfo ignore : params) { - count++; - InjectionPointInfo ipInfo = TypeTools.createInjectionPointInfo(serviceTypeName, methodInfo, count); - continuation = continuation.add(ipInfo); - } - } - } - return continuation; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorRequestBlueprint.java deleted file mode 100644 index f1fca86f183..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorRequestBlueprint.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.inject.api.Qualifier; - -/** - * The request payload that is used by {@link io.helidon.inject.tools.spi.ExternalModuleCreator}. - *

- * Note that the thread context classloader should be setup appropriately so that service types can be resolved - * based upon the packages requested to scan. - */ -@Prototype.Blueprint -interface ExternalModuleCreatorRequestBlueprint extends GeneralCreatorRequestBlueprint { - - /** - * The set of packages to analyze and eventually generate activators against. - * - * @return the list of package names to analyze and target for activator creation - */ - @Option.Singular - List packageNamesToScan(); - - /** - * Optionally, provides a means to map additional qualifiers to service types. - * - * @return any qualifiers that should be mapped into the generated services - */ - @Option.Singular - Map> serviceTypeToQualifiersMap(); - - /** - * Config options w.r.t. planned activator creation. - * - * @return the config options for activator creation - */ - ActivatorCreatorConfigOptions activatorCreatorConfigOptions(); - - /** - * Optionally, set this to allow inner classes to be processed for potential activators. - * - * @return allows inner classes to be processed for potential activators - */ - boolean innerClassesProcessed(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorResponseBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorResponseBlueprint.java deleted file mode 100644 index 9bcd24ececb..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ExternalModuleCreatorResponseBlueprint.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.builder.api.Prototype; - -/** - * The response from {@link io.helidon.inject.tools.spi.ExternalModuleCreator}. - *

- * The response, if successful, will contribute to the {@link ActivatorCreatorRequest} - * passed to {@link io.helidon.inject.tools.spi.ActivatorCreator} in any next phase of creation for the external module. - */ -@Prototype.Blueprint -interface ExternalModuleCreatorResponseBlueprint extends GeneralCreatorResponseBlueprint { - - /** - * The activator creator request. - * - * @return the activator creator request - */ - ActivatorCreatorRequest activatorCreatorRequest(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCodeGenDetailBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCodeGenDetailBlueprint.java deleted file mode 100644 index d1bf12a5df3..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCodeGenDetailBlueprint.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * Generically describes the source code generated. - */ -@Prototype.Blueprint -interface GeneralCodeGenDetailBlueprint { - - /** - * The FQN of the source that was generated. - * - * @return the FQN name for the code that was generated - */ - TypeName serviceTypeName(); - - /** - * Optionally, the source code generated. - * - * @return the body of the source, or empty if unknown or unavailable - */ - Optional body(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCodeGenNamesBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCodeGenNamesBlueprint.java deleted file mode 100644 index aa9619dff79..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCodeGenNamesBlueprint.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * General code gen information. - */ -@Prototype.Blueprint -interface GeneralCodeGenNamesBlueprint { - - /** - * Optionally, the name of the template to apply, defaulting to "default". - * - * @return the template name that should be used - */ - @ConfiguredOption("default") - String templateName(); - - /** - * The module name. - * This name is used primarily to serve as the codegen name for the {@link io.helidon.inject.api.ModuleComponent} that is - * generated. - * - * @return module name - */ - Optional moduleName(); - - /** - * The package name to use for the generated {@link io.helidon.inject.api.ModuleComponent}, - * {@link io.helidon.inject.api.Application}, etc. - * If one is not provided, one will be determined internally. - * - * @return the suggested package name, otherwise passing null will delegate package naming to the implementation heuristic - */ - Optional packageName(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCreatorRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCreatorRequestBlueprint.java deleted file mode 100644 index 351bdce4005..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCreatorRequestBlueprint.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Optional; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Base interface codegen-related requests. - */ -@Prototype.Blueprint -interface GeneralCreatorRequestBlueprint extends GeneralCodeGenNamesBlueprint { - - /** - * Set to true to avoid code-generating, and instead provide the plan for what would be built. - * - * @return if set to true then no codegen will occur on disk - */ - @ConfiguredOption("false") - boolean analysisOnly(); - - /** - * Where codegen should be read and written. - * - * @return the code paths to use for reading and writing artifacts - */ - Optional codeGenPaths(); - - /** - * Optionally, any compiler options to pass explicitly to the java compiler. Not applicable during annotation processing. - * - * @return explicit compiler options - */ - Optional compilerOptions(); - - /** - * The complete list of service type names belonging to the {@link io.helidon.inject.api.ModuleComponent}. - *

- * Assumptions: - *

    - *
  • The service type is available for reflection/introspection at creator invocation time (typically at - * compile time). - *
- * - * @return the complete list of service type names - */ - List serviceTypeNames(); - - /** - * The complete list of service type names that should be code generated into {@link io.helidon.inject.api.Activator}'s. - * - * @return the complete list of service type names to code generated - */ - List generatedServiceTypeNames(); - - /** - * Should exceptions be thrown, or else captured in the response under {@link ActivatorCreatorResponse#error()}. - * The default is true. - * - * @return true if the creator should fail, otherwise the response will show the error - */ - @ConfiguredOption("true") - boolean throwIfError(); - - /** - * Provides the generator (used to append to code generated artifacts in {@code javax.annotation.processing.Generated} - * annotations). - * - * @return the generator name - */ - Optional generator(); - - /** - * The code gen filer to use. - * - * @return the code gen filer - */ - CodeGenFiler filer(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCreatorResponseBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCreatorResponseBlueprint.java deleted file mode 100644 index 914e114ed5b..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/GeneralCreatorResponseBlueprint.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * General base interface for any codegen-related create activity. - */ -@Prototype.Blueprint -interface GeneralCreatorResponseBlueprint extends GeneralCodeGenNamesBlueprint { - - /** - * Flag to indicate a success or failure. - * - * @return success flag - */ - @ConfiguredOption("true") - boolean success(); - - /** - * Any error that was caught during processing. - * - * @return any error that was thrown - */ - Optional error(); - - // java source related ... - - /** - * The services that were generated. - * - * @return the services that were generated - */ - List serviceTypeNames(); - - /** - * The detailed information generated for those service type involved in code generation. - * - * @return map of service type names to generated details - */ - @Option.Singular - Map serviceTypeDetails(); - - // resources related ... - - /** - * The META-INF services entries. - * - * @return the META-INF services entries - */ - Map> metaInfServices(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/GenericTemplateCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/GenericTemplateCreator.java deleted file mode 100644 index 8dfe964d980..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/GenericTemplateCreator.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; - -import io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator; - -/** - * Tools to assist with using {@link CustomAnnotationTemplateCreator}'s. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface GenericTemplateCreator { - - /** - * Convenience method to help with the typical/generic case where the request + the provided generatedType - * is injected into the supplied template to produce the response. - * - * @param request the generic template creator request - * - * @return the response, or empty if the template can not be generated for this case - */ - Optional create(GenericTemplateCreatorRequest request); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/GenericTemplateCreatorRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/GenericTemplateCreatorRequestBlueprint.java deleted file mode 100644 index b005367200f..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/GenericTemplateCreatorRequestBlueprint.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Map; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * This builder represents the request arguments to pass to the {@link GenericTemplateCreator}. - */ -@Prototype.Blueprint -interface GenericTemplateCreatorRequestBlueprint { - - /** - * The custom annotation template request. - * - * @return the custom annotation template request - */ - CustomAnnotationTemplateRequest customAnnotationTemplateRequest(); - - /** - * The type name that should will be code generated. - * - * @return the type name that will be code generated - */ - TypeName generatedTypeName(); - - /** - * The (mustache / handlebars) template. - * - * @return the (mustache / handlebars) template - */ - CharSequence template(); - - /** - * The overriding properties to apply that will supersede the default values that are specified below. - *
    - *
  • properties.put("generatedSticker", {generated-sticker}); - *
  • properties.put("generatedTypeName", req.getGeneratedTypeName().getName()); - *
  • properties.put("annoTypeName", TypeNameImpl.toName(req.getAnnoType())); - *
  • properties.put("packageName", req.getGeneratedTypeName().getPackageName()); - *
  • properties.put("className", req.getGeneratedTypeName().getClassName()); - *
  • properties.put("enclosingClassTypeName", req.getEnclosingClassType().getName()); - *
  • properties.put("enclosingClassAnnotations", req.getEnclosingClassAnnotations()); - *
  • properties.put("basicServiceInfo", req.getBasicServiceInfo()); - *
  • properties.put("weight", ServiceInfo.weightOf(req.getBasicServiceInfo()); - *
  • properties.put("enclosingClassTypeName.packageName", req.getEnclosingClassType().getPackageName()); - *
  • properties.put("enclosingClassTypeName.className", req.getEnclosingClassType().getClassName()); - *
  • properties.put("elementKind", req.getElementKind()); - *
  • properties.put("elementName", req.getElementName()); - *
  • properties.put("elementAccess", req.getElementAccess()); - *
  • properties.put("elementIsStatic", req.isElementStatic()); - *
  • properties.put("elementEnclosingTypeName", req.getElementEnclosingType().getName()); - *
  • properties.put("elementEnclosingTypeName.packageName", req.getElementEnclosingType().getPackageName()); - *
  • properties.put("elementEnclosingTypeName.className", req.getElementEnclosingType().getClassName()); - *
  • properties.put("elementArgs", req.getElementArgs()); - *
  • properties.put("elementArgs-declaration", req.getElementArgs()); - *
- * - * @return the overriding properties to apply - */ - Map overrideProperties(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/IdAndToString.java b/inject/tools/src/main/java/io/helidon/inject/tools/IdAndToString.java deleted file mode 100644 index 6e6ca3ff6af..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/IdAndToString.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.function.Function; -import java.util.stream.Collectors; - -/** - * Convenience for use with handlebars to offer {{id}} that is different from {{.}}. - */ -class IdAndToString { - - private final String id; - private final Object toString; - - /** - * Constructor. - * - * @param id the id - * @param toString the toString value - */ - IdAndToString(String id, - Object toString) { - this.id = Objects.requireNonNull(id); - this.toString = toString; - } - - /** - * Returns the id. - * - * @return the id - */ - // note that this is called from Mustache, so it needs to be bean-style named! - public String getId() { - return id; - } - - @Override - public String toString() { - return String.valueOf(toString); - } - - @Override - public int hashCode() { - return getId().hashCode(); - } - - @Override - public boolean equals(Object another) { - if (!(another instanceof IdAndToString)) { - return false; - } - return getId().equals(((IdAndToString) another).getId()); - } - - /** - * Creates a list of {@link IdAndToString} from a list of T's. - * - * @param list the list to convert - * @param toId the function that will create the {@link IdAndToString} - * @param the type of the list - * @return the converted list - */ - static List toList(Collection list, - Function toId) { - if (list == null) { - return null; - } - - return list.stream() - .map(toId) - .collect(Collectors.toList()); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/InjectionSupported.java b/inject/tools/src/main/java/io/helidon/inject/tools/InjectionSupported.java deleted file mode 100644 index 57d3670161e..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/InjectionSupported.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.common.types.TypeName; - -/** - * Centralized utility to help callers determine what is and is not supported. - */ -class InjectionSupported { - - private InjectionSupported() { - } - - /** - * Returns true if the targetElement can be supported within the model as an injection point target. - * - * @param logger the optional logger to use if not supported - * @param serviceType the enclosing service type - * @param targetElement the target element description - * @param isPrivate is the target element private - * @param isStatic is the target element static - * @return true if the target supports injection, false otherwise (assuming not throwIfNotSupported) - */ - static boolean isSupportedInjectionPoint(System.Logger logger, - TypeName serviceType, - Object targetElement, - boolean isPrivate, - boolean isStatic) { - boolean supported = (!isPrivate && !isStatic); - if (!supported) { - String message = "static and private injection points are not supported: " + serviceType + "." + targetElement; - if (logger != null) { - System.Logger.Level level = System.Logger.Level.WARNING; - logger.log(level, message); - } - } - return supported; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptedElementBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/InterceptedElementBlueprint.java deleted file mode 100644 index 7faacde2b34..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptedElementBlueprint.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Set; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * Used in the interception model described by {@link InterceptionPlan}. An intercepted - * element typically refers to a {@link io.helidon.inject.api.ElementKind#CONSTRUCTOR} or - * {@link io.helidon.inject.api.ElementKind#METHOD} that qualifies for interception. If, however, - * the {@link io.helidon.inject.api.InterceptedTrigger} is applied on the enclosing service type then all public methods. - * Note that only public methods on Helidon injection-activated services can be intercepted. - */ -@Prototype.Blueprint -interface InterceptedElementBlueprint { - - /** - * The set of {@link io.helidon.inject.api.InterceptedTrigger} types that apply to this method/element. - * - * @return the set of intercepted trigger types that apply to this method/element - */ - Set interceptedTriggerTypeNames(); - - /** - * The method element info for this intercepted method. - * - * @return the method element info for this intercepted method - */ - MethodElementInfo elementInfo(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptionPlanBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/InterceptionPlanBlueprint.java deleted file mode 100644 index 276be25b9d8..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptionPlanBlueprint.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Set; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; - -/** - * Once a service type qualifies for interception, the interception plan will be created describing how the service type - * should be intercepted. - */ -@Prototype.Blueprint -interface InterceptionPlanBlueprint { - - /** - * The intercepted service. - * - * @return the intercepted service - */ - io.helidon.inject.api.ServiceInfoBasics interceptedService(); - - /** - * Annotations at the service type level. - * - * @return annotations at the service type level - */ - Set serviceLevelAnnotations(); - - /** - * Returns true if the implementation has a zero/no-argument constructor. - * - * @return true if the service type being intercepted has a zero/no-argument constructor - */ - boolean hasNoArgConstructor(); - - /** - * The interfaces that this service implements (usually a superset of - * {@link io.helidon.inject.api.ServiceInfoBasics#contractsImplemented()}). - * - * @return the interfaces implemented - */ - Set interfaces(); - - /** - * All the annotation names that contributed to triggering this interceptor plan. - * - * @return all the annotation names that contributed to triggering this interceptor plan - */ - Set annotationTriggerTypeNames(); - - /** - * The list of elements that should be intercepted. - * - * @return the list of elements that should be intercepted - */ - List interceptedElements(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorDefault.java b/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorDefault.java deleted file mode 100644 index c57c801b7be..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorDefault.java +++ /dev/null @@ -1,1226 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -import io.helidon.common.LazyValue; -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.common.processor.AnnotationFactory; -import io.helidon.common.processor.CopyrightHandler; -import io.helidon.common.processor.TypeFactory; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ElementInfo; -import io.helidon.inject.api.InterceptedTrigger; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.tools.spi.InterceptorCreator; - -import io.github.classgraph.ClassInfo; -import io.github.classgraph.MethodInfo; -import io.github.classgraph.MethodTypeSignature; -import io.github.classgraph.ScanResult; -import jakarta.inject.Singleton; - -import static io.helidon.inject.api.ServiceInfoBasics.DEFAULT_INJECT_WEIGHT; -import static io.helidon.inject.tools.TypeTools.createAnnotationListFromAnnotations; -import static io.helidon.inject.tools.TypeTools.createAnnotationSet; -import static io.helidon.inject.tools.TypeTools.createMethodElementInfo; -import static io.helidon.inject.tools.TypeTools.gatherAllAnnotationsUsedOnPublicNonStaticMethods; -import static io.helidon.inject.tools.TypeTools.toKind; - -/** - * The default {@link InterceptorCreator} provider in use. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Singleton -@Weight(DEFAULT_INJECT_WEIGHT) -@SuppressWarnings("unchecked") -public class InterceptorCreatorDefault extends AbstractCreator implements InterceptorCreator, Resettable { - private static final LazyValue SCAN = LazyValue.create(ReflectionHandler.INSTANCE::scan); - - private static final String INTERCEPTOR_NAME_SUFFIX = "Interceptor"; - private static final String INNER_INTERCEPTOR_CLASS_NAME = "$$" + NAME_PREFIX + INTERCEPTOR_NAME_SUFFIX; - private static final String NO_ARG_INTERCEPTOR_HBS = "no-arg-based-interceptor.hbs"; - private static final String INTERFACES_INTERCEPTOR_HBS = "interface-based-interceptor.hbs"; - private static final double INTERCEPTOR_PRIORITY_DELTA = 0.001; - private static final String CTOR_ALIAS = "ctor"; - /** - * the interceptor meta-annotation. - */ - private static final Annotation TRIGGER = Annotation.create(InterceptedTrigger.class); - private static final TypeName TRIGGER_TYPE = TRIGGER.typeName(); - private static final Set ALLOW_LIST = new LinkedHashSet<>(); - - private final Set allowListedAnnoTypeNames = new LinkedHashSet<>(); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public InterceptorCreatorDefault() { - super(TemplateHelper.DEFAULT_TEMPLATE_NAME); - } - - @Override - public boolean reset(boolean deep) { - allowListedAnnoTypeNames.clear(); - return true; - } - - /** - * Sets the allow-listed annotation types triggering interception creation for the default interceptor creator. - * - * @param allowListedAnnotationTypes the allow-listed annotation types - * @return this instance - */ - public InterceptorCreatorDefault allowListedAnnotationTypes(Set allowListedAnnotationTypes) { - this.allowListedAnnoTypeNames.addAll(allowListedAnnotationTypes); - return this; - } - - @Override - public Set allowListedAnnotationTypes() { - return allowListedAnnoTypeNames; - } - - /** - * Abstract base for handling the resolution of annotation types by name. - */ - abstract static class AnnotationTypeNameResolver { - /** - * Determine the all the annotations belonging to a particular annotation type name. - * - * @param annoTypeName the annotation type name - * @return the list of (meta) annotations for the given annotation - */ - abstract Collection resolve(TypeName annoTypeName); - } - - static class ProcessorResolver extends AnnotationTypeNameResolver { - private final Elements elements; - - ProcessorResolver(Elements elements) { - this.elements = elements; - } - - @Override - public Collection resolve(TypeName annoTypeName) { - TypeElement typeElement = elements.getTypeElement(annoTypeName.fqName()); - - if (typeElement == null) { - throw new ToolsException("Unable to resolve: " + annoTypeName); - } - - List annotations = typeElement.getAnnotationMirrors(); - return annotations.stream() - .map(it -> AnnotationFactory.createAnnotation(it, elements)) - .collect(Collectors.toSet()); - } - } - - static class ReflectionResolver extends AnnotationTypeNameResolver { - private final ScanResult scan; - - ReflectionResolver(ScanResult scan) { - this.scan = scan; - } - - @Override - public Collection resolve(TypeName annoTypeName) { - ClassInfo classInfo = scan.getClassInfo(annoTypeName.fqName()); - if (classInfo == null) { - try { - Class annotationType = - (Class) Class.forName(annoTypeName.fqName()); - return createAnnotationListFromAnnotations(annotationType.getAnnotations()); - } catch (ClassNotFoundException e) { - throw new ToolsException(e.getMessage(), e); - } - } - return createAnnotationSet(classInfo); - } - } - - /** - * Filter will apply the appropriate strategy determine which annotation types qualify as triggers for interception. - */ - abstract static class TriggerFilter { - /** - * The creator. - */ - private final InterceptorCreator creator; - - /** - * The way to convert a string to the annotation type. - */ - private final AnnotationTypeNameResolver resolver; - - protected TriggerFilter() { - this.creator = null; - this.resolver = null; - } - - protected TriggerFilter(InterceptorCreator creator) { - this.creator = Objects.requireNonNull(creator); - this.resolver = null; - } - - protected TriggerFilter(InterceptorCreator creator, - AnnotationTypeNameResolver resolver) { - this.creator = Objects.requireNonNull(creator); - this.resolver = Objects.requireNonNull(resolver); - } - - Optional creator() { - return Optional.ofNullable(creator); - } - - Optional resolver() { - return Optional.ofNullable(resolver); - } - - /** - * Returns true if the annotation qualifies/triggers interceptor creation. - * - * @param annotationTypeName the annotation type name - * @return true if the annotation qualifies/triggers interceptor creation - */ - boolean isQualifyingTrigger(TypeName annotationTypeName) { - return (creator != null) && creator.isAllowListed(annotationTypeName); - } - } - - /** - * Enforces {@link Strategy#EXPLICIT}. - */ - private static class ExplicitStrategy extends TriggerFilter { - protected ExplicitStrategy(InterceptorCreator creator, - AnnotationTypeNameResolver resolver) { - super(creator, resolver); - } - - @Override - public boolean isQualifyingTrigger(TypeName annotationTypeName) { - return resolver().map(it -> it.resolve(annotationTypeName).contains(TRIGGER)) - .orElse(false) - || TRIGGER_TYPE.equals(annotationTypeName); - } - } - - /** - * Enforces {@link Strategy#ALL_RUNTIME}. - */ - private static class AllRuntimeStrategy extends TriggerFilter { - protected static final Annotation RUNTIME = Annotation.create(Retention.class, RetentionPolicy.RUNTIME.name()); - protected static final Annotation CLASS = Annotation.create(Retention.class, RetentionPolicy.CLASS.name()); - - protected AllRuntimeStrategy(InterceptorCreator creator, - AnnotationTypeNameResolver resolver) { - super(creator, resolver); - } - - @Override - public boolean isQualifyingTrigger(TypeName annotationTypeName) { - Objects.requireNonNull(annotationTypeName); - if (ALLOW_LIST.contains(annotationTypeName)) { - return true; - } - return resolver().map(resolver -> resolver.resolve(annotationTypeName).contains(RUNTIME) - || resolver.resolve(annotationTypeName).contains(CLASS)) - .orElse(false); - } - } - - /** - * Enforces {@link Strategy#ALLOW_LISTED}. - */ - private static class AllowListedStrategy extends TriggerFilter { - private final Set allowListed; - - protected AllowListedStrategy(InterceptorCreator creator) { - super(creator); - this.allowListed = Objects.requireNonNull(creator.allowListedAnnotationTypes()); - } - - @Override - public boolean isQualifyingTrigger(TypeName annotationTypeName) { - Objects.requireNonNull(annotationTypeName); - return allowListed.contains(annotationTypeName) || ALLOW_LIST.contains(annotationTypeName); - } - } - - /** - * Enforces {@link Strategy#CUSTOM}. - */ - private static class CustomStrategy extends TriggerFilter { - protected CustomStrategy(InterceptorCreator creator) { - super(creator); - } - - @Override - public boolean isQualifyingTrigger(TypeName annotationTypeName) { - Objects.requireNonNull(annotationTypeName); - if (ALLOW_LIST.contains(annotationTypeName)) { - return true; - } - - return creator().map(it -> it.isAllowListed(annotationTypeName)) - .orElse(false); - } - } - - /** - * Enforces {@link Strategy#NONE}. - */ - private static class NoneStrategy extends TriggerFilter { - } - - /** - * Enforces {@link Strategy#BLENDED}. - */ - private static class BlendedStrategy extends ExplicitStrategy { - private final CustomStrategy customStrategy; - - protected BlendedStrategy(InterceptorCreator creator, - AnnotationTypeNameResolver resolver) { - super(creator, resolver); - this.customStrategy = new CustomStrategy(creator); - } - - @Override - public boolean isQualifyingTrigger(TypeName annotationTypeName) { - if (super.isQualifyingTrigger(annotationTypeName)) { - return true; - } - return customStrategy.isQualifyingTrigger(annotationTypeName); - } - } - - /** - * Returns the {@link TriggerFilter} appropriate for the given {@link InterceptorCreator}. - * - * @param creator the interceptor creator - * @param resolver the resolver, used in cases where the implementation needs to research more about a given annotation type - * @return the trigger filter instance - */ - private static TriggerFilter createTriggerFilter(InterceptorCreator creator, - AnnotationTypeNameResolver resolver) { - Strategy strategy = creator.strategy(); - if (Strategy.EXPLICIT == strategy) { - return new ExplicitStrategy(creator, resolver); - } else if (Strategy.ALL_RUNTIME == strategy) { - return new AllRuntimeStrategy(creator, resolver); - } else if (Strategy.ALLOW_LISTED == strategy) { - return new AllowListedStrategy(creator); - } else if (Strategy.CUSTOM == strategy) { - return new CustomStrategy(creator); - } else if (Strategy.NONE == strategy) { - return new NoneStrategy(); - } else if (Strategy.BLENDED == strategy || strategy == null) { - return new BlendedStrategy(creator, resolver); - } else { - throw new ToolsException("Unknown strategy: " + strategy); - } - } - - /** - * Able to abstractly handle processing in annotation processing mode, or in reflection mode. - */ - @SuppressWarnings("checkstyle:VisibilityModifier") - abstract static class AbstractInterceptorProcessor implements InterceptorProcessor { - /** - * The service being intercepted/processed. - */ - final ServiceInfoBasics interceptedService; - - /** - * The "real" / delegate creator. - */ - final InterceptorCreator creator; - - private final AnnotationTypeNameResolver resolver; - private final TriggerFilter triggerFilter; - private final System.Logger logger; - - protected AbstractInterceptorProcessor(ServiceInfoBasics interceptedService, - InterceptorCreator realCreator, - AnnotationTypeNameResolver resolver, - System.Logger logger) { - this.creator = realCreator; - this.interceptedService = interceptedService; - this.resolver = resolver; - this.triggerFilter = createTriggerFilter(realCreator, resolver); - this.logger = logger; - } - - TypeName serviceTypeName() { - return interceptedService.serviceTypeName(); - } - - /** - * @return the trigger filter in use - */ - TriggerFilter triggerFilter() { - return triggerFilter; - } - - /** - * The set of annotation types that trigger interception. - * - * @return the set of annotation types that are trigger interception - */ - @Override - public Set allAnnotationTypeTriggers() { - Set allAnnotations = getAllAnnotations(); - if (allAnnotations.isEmpty()) { - return Set.of(); - } - - TriggerFilter triggerFilter = triggerFilter(); - // the below section uses a linked has set to make sure the order is preserved - // so we can run tests that depend on that order (such as actual generated code) - return allAnnotations.stream() - .filter(triggerFilter::isQualifyingTrigger) - .filter(Predicate.not(TRIGGER_TYPE::equals)) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - @Override - public Optional createInterceptorPlan(Set interceptorAnnotationTriggers) { - boolean hasNoArgConstructor = hasNoArgConstructor(); - Set interfaces = interfaces(); - - // the code generation will extend the class when there is a zero/no-arg constructor, but if not then we will use a - // different generated source altogether that will only allow the interception of the interfaces. - // note also that the service type, or the method has to have the interceptor trigger annotation to qualify. - if (!hasNoArgConstructor && interfaces.isEmpty()) { - String msg = "There must either be a no-arg constructor, or otherwise the target service must implement at least " - + "one interface type. Note that when a no-arg constructor is available then your entire type, including " - + "all of its public methods are interceptable. If, however, there is no applicable no-arg constructor " - + "available then only the interface-based methods of the target service type are interceptable for: " - + serviceTypeName(); - ToolsException te = new ToolsException(msg); - logger.log(System.Logger.Level.ERROR, "Unable to create an interceptor plan for: " + serviceTypeName(), te); - throw te; - } - - List interceptedElements = (hasNoArgConstructor) - ? getInterceptedElements(interceptorAnnotationTriggers) - : getInterceptedElements(interceptorAnnotationTriggers, interfaces); - if (interceptedElements.isEmpty()) { - ToolsException te = new ToolsException("No methods available to intercept for: " + serviceTypeName()); - logger.log(System.Logger.Level.ERROR, "Unable to create an interceptor plan for: " + serviceTypeName(), te); - throw te; - } - - Set serviceLevelAnnotations = getServiceLevelAnnotations(); - InterceptionPlan plan = InterceptionPlan.builder() - .interceptedService(interceptedService) - .serviceLevelAnnotations(serviceLevelAnnotations) - .annotationTriggerTypeNames(interceptorAnnotationTriggers) - .interceptedElements(interceptedElements) - .hasNoArgConstructor(hasNoArgConstructor) - .interfaces(interfaces) - .build(); - return Optional.of(plan); - } - - @Override - public String toString() { - return serviceTypeName().resolvedName(); - } - - /** - * @return the cumulative annotations referenced by this type - */ - abstract Set getAllAnnotations(); - - /** - * @return only the service level annotations referenced by this type - */ - abstract Set getServiceLevelAnnotations(); - - /** - * @return true if there is a no-arg constructor present - */ - abstract boolean hasNoArgConstructor(); - - /** - * @return the set of interfaces implemented - */ - abstract Set interfaces(); - - /** - * @return all public methods - */ - abstract List getInterceptedElements(Set interceptorAnnotationTriggers); - - /** - * @return all public methods for only the given interfaces - */ - abstract List getInterceptedElements(Set interceptorAnnotationTriggers, - Set interfaces); - - boolean containsAny(Set annotations, - Set annotationTypeNames) { - for (Annotation annotation : annotations) { - if (annotationTypeNames.contains(annotation.typeName())) { - return true; - } - } - return false; - } - - boolean isProcessed(ElementKind kind, - Set modifiers, - Boolean isPrivate, - Boolean isStatic) { - assert (ElementKind.CONSTRUCTOR == kind || ElementKind.METHOD == kind) - : kind + " in:" + serviceTypeName(); - - if (modifiers != null) { - if (modifiers.contains(Modifier.STATIC)) { - return false; - } - - if (modifiers.contains(Modifier.PRIVATE)) { - return false; - } - } else { - if (isPrivate) { - return false; - } - - if (isStatic) { - return false; - } - } - - return true; - } - } - - - private static class ProcessorBased extends AbstractInterceptorProcessor { - private final TypeElement serviceTypeElement; - private final ProcessingEnvironment processEnv; - - ProcessorBased(ServiceInfoBasics interceptedService, - InterceptorCreator realCreator, - ProcessingEnvironment processEnv, - System.Logger logger) { - super(interceptedService, realCreator, createResolverFromProcessor(processEnv), logger); - - TypeElement typeElement = processEnv.getElementUtils().getTypeElement(serviceTypeName().resolvedName()); - if (typeElement == null) { - throw new ToolsException("Failed to get type element for " + serviceTypeName()); - } - - this.serviceTypeElement = typeElement; - this.processEnv = processEnv; - } - - @Override - Set getAllAnnotations() { - Set set = gatherAllAnnotationsUsedOnPublicNonStaticMethods(serviceTypeElement, processEnv); - return set.stream() - .map(a -> a.typeName()) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - @Override - Set getServiceLevelAnnotations() { - return AnnotationFactory.createAnnotations(serviceTypeElement, processEnv.getElementUtils()); - } - - @Override - boolean hasNoArgConstructor() { - return serviceTypeElement.getEnclosedElements() - .stream() - .filter(it -> it.getKind().equals(ElementKind.CONSTRUCTOR)) - .map(ExecutableElement.class::cast) - .anyMatch(it -> it.getParameters().isEmpty()); - } - - @Override - Set interfaces() { - return gatherInterfaces(new LinkedHashSet<>(), serviceTypeElement); - } - - Set gatherInterfaces(Set result, - TypeElement typeElement) { - if (typeElement == null) { - return result; - } - - typeElement.getInterfaces().forEach(tm -> { - result.add(TypeFactory.createTypeName(tm).orElseThrow()); - gatherInterfaces(result, TypeTools.toTypeElement(tm).orElse(null)); - }); - - TypeElement te = (TypeElement) processEnv.getTypeUtils().asElement(typeElement.getSuperclass()); - return gatherInterfaces(result, te); - } - - @Override - List getInterceptedElements(Set interceptorAnnotationTriggers) { - List result = new ArrayList<>(); - Set serviceLevelAnnos = getServiceLevelAnnotations(); - - // find the injectable constructor, falling back to the no-arg constructor - gatherInjectableConstructor(result, serviceLevelAnnos, interceptorAnnotationTriggers); - - // gather all of the public methods as well as the no-arg constructor - serviceTypeElement.getEnclosedElements().stream() - .filter(e -> e.getKind() == ElementKind.METHOD) - .map(ExecutableElement.class::cast) - .filter(e -> isProcessed(toKind(e), /*e.getParameters().size(),*/ e.getModifiers(), null, null)) - .forEach(ee -> result.add( - create(processEnv, ee, serviceLevelAnnos, interceptorAnnotationTriggers))); - return result; - } - - @Override - List getInterceptedElements(Set interceptorAnnotationTriggers, - Set interfaces) { - assert (!interfaces.isEmpty()); - List result = new ArrayList<>(); - Set serviceLevelAnnos = getServiceLevelAnnotations(); - - // find the injectable constructor, falling back to the no-arg constructor - gatherInjectableConstructor(result, serviceLevelAnnos, interceptorAnnotationTriggers); - - // gather all of the methods that map to one of our interfaces - serviceTypeElement.getEnclosedElements().stream() - .filter(e -> e.getKind() == ElementKind.METHOD) - .map(ExecutableElement.class::cast) - .filter(e -> isProcessed(toKind(e), e.getModifiers(), null, null)) - .filter(e -> mapsToAnInterface(e, interfaces)) - .forEach(ee -> result.add( - create(processEnv, ee, serviceLevelAnnos, interceptorAnnotationTriggers))); - return result; - } - - void gatherInjectableConstructor(List result, - Set serviceLevelAnnos, - Set interceptorAnnotationTriggers) { - serviceTypeElement.getEnclosedElements().stream() - .filter(e -> e.getKind() == ElementKind.CONSTRUCTOR) - .map(ExecutableElement.class::cast) - .filter(ee -> !ee.getModifiers().contains(Modifier.PRIVATE)) - .filter(ee -> { - boolean hasInject = ee.getAnnotationMirrors().stream() - .map(it -> AnnotationFactory.createAnnotation(it, processEnv.getElementUtils())) - .map(Annotation::typeName) - .map(TypeName::name) - .anyMatch(anno -> TypeNames.JAKARTA_INJECT.equals(anno) || TypeNames.JAVAX_INJECT.equals(anno)); - return hasInject; - }) - .forEach(ee -> result.add( - create(processEnv, ee, serviceLevelAnnos, interceptorAnnotationTriggers))); - - if (result.size() > 1) { - throw new ToolsException("There can be at most one injectable constructor for: " + serviceTypeName()); - } - - if (result.size() == 1) { - return; - } - - // find the no-arg constructor as the fallback - serviceTypeElement.getEnclosedElements().stream() - .filter(e -> e.getKind() == ElementKind.CONSTRUCTOR) - .map(ExecutableElement.class::cast) - .filter(ee -> !ee.getModifiers().contains(Modifier.PRIVATE)) - .filter(ee -> ee.getParameters().isEmpty()) - .forEach(ee -> result.add( - create(processEnv, ee, serviceLevelAnnos, interceptorAnnotationTriggers))); - if (result.isEmpty()) { - throw new ToolsException("There should either be a no-arg or injectable constructor for: " + serviceTypeName()); - } - } - - /** - * @return returns true if the given method is implemented in one of the provided interface type names - */ - boolean mapsToAnInterface(ExecutableElement ee, - Set interfaces) { - for (TypeName typeName : interfaces) { - TypeElement te = processEnv.getElementUtils().getTypeElement(typeName.name()); - Objects.requireNonNull(te, typeName.toString()); - boolean hasIt = te.getEnclosedElements().stream() - // _note to self_: there needs to be a better way than this! - .anyMatch(e -> e.toString().equals(ee.toString())); - if (hasIt) { - return true; - } - } - return false; - } - - private InterceptedElement create(ProcessingEnvironment processingEnv, - ExecutableElement ee, - Set serviceLevelAnnos, - Set interceptorAnnotationTriggers) { - MethodElementInfo elementInfo = createMethodElementInfo(processingEnv, serviceTypeElement, ee, serviceLevelAnnos); - Set applicableTriggers = new LinkedHashSet<>(interceptorAnnotationTriggers); - applicableTriggers.retainAll(elementInfo.annotations() - .stream() - .map(a -> a.typeName()) - .collect(Collectors.toSet())); - return InterceptedElement.builder() - .interceptedTriggerTypeNames(applicableTriggers) - .elementInfo(elementInfo) - .build(); - } - } - - - private static class ReflectionBased extends AbstractInterceptorProcessor { - private final ClassInfo classInfo; - - ReflectionBased(ServiceInfoBasics interceptedService, - InterceptorCreator realCreator, - ClassInfo classInfo, - System.Logger logger) { - super(/*serviceTypeName,*/ interceptedService, realCreator, createResolverFromReflection(), logger); - this.classInfo = classInfo; - } - - @Override - Set getAllAnnotations() { - Set set = gatherAllAnnotationsUsedOnPublicNonStaticMethods(classInfo); - return set.stream() - .map(a -> a.typeName()) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - @Override - Set getServiceLevelAnnotations() { - return createAnnotationSet(classInfo); - } - - @Override - boolean hasNoArgConstructor() { - return classInfo.getConstructorInfo().stream() - .filter(mi -> !mi.isPrivate()) - .anyMatch(mi -> mi.getParameterInfo().length == 0); - } - - @Override - Set interfaces() { - return gatherInterfaces(new LinkedHashSet<>(), classInfo); - } - - Set gatherInterfaces(Set result, - ClassInfo classInfo) { - if (classInfo == null) { - return result; - } - - classInfo.getInterfaces().forEach(tm -> { - result.add(TypeTools.createTypeNameFromClassInfo(tm)); - gatherInterfaces(result, tm); - }); - - return gatherInterfaces(result, classInfo.getSuperclass()); - } - - @Override - List getInterceptedElements(Set interceptorAnnotationTriggers) { - List result = new ArrayList<>(); - Set serviceLevelAnnos = getServiceLevelAnnotations(); - classInfo.getMethodAndConstructorInfo() - .filter(m -> isProcessed(toKind(m), /*m.getParameterInfo().length,*/ null, m.isPrivate(), m.isStatic())) - .filter(m -> containsAny(serviceLevelAnnos, interceptorAnnotationTriggers) - || containsAny(createAnnotationSet(m.getAnnotationInfo()), interceptorAnnotationTriggers)) - .forEach(mi -> result.add( - create(mi, serviceLevelAnnos, interceptorAnnotationTriggers))); - return result; - } - - @Override - List getInterceptedElements(Set interceptorAnnotationTriggers, - Set interfaces) { - List result = new ArrayList<>(); - Set serviceLevelAnnos = getServiceLevelAnnotations(); - classInfo.getMethodAndConstructorInfo() - .filter(m -> isProcessed(toKind(m), null, m.isPrivate(), m.isStatic())) - .filter(m -> containsAny(serviceLevelAnnos, interceptorAnnotationTriggers) - || containsAny(createAnnotationSet(m.getAnnotationInfo()), interceptorAnnotationTriggers)) - .filter(m -> mapsToAnInterface(m, interfaces)) - .forEach(mi -> result.add( - create(mi, serviceLevelAnnos, interceptorAnnotationTriggers))); - return result; - } - - boolean mapsToAnInterface(MethodInfo targetMethodInfo, - Set interfaces) { - MethodTypeSignature sig = targetMethodInfo.getTypeSignatureOrTypeDescriptor(); - for (TypeName typeName : interfaces) { - ClassInfo ci = toClassInfo(typeName, classInfo); - Objects.requireNonNull(ci, typeName.toString()); - for (MethodInfo mi : ci.getDeclaredMethodInfo(targetMethodInfo.getName())) { - if (mi.equals(targetMethodInfo) || sig.equals(mi.getTypeSignatureOrTypeDescriptor())) { - return true; - } - } - } - return false; - } - - ClassInfo toClassInfo(TypeName typeName, - ClassInfo child) { - for (ClassInfo ci : child.getInterfaces()) { - if (TypeTools.createTypeNameFromClassInfo(ci).equals(typeName)) { - return ci; - } - } - - for (ClassInfo ci : child.getSuperclasses()) { - ClassInfo foundIt = toClassInfo(typeName, ci); - if (foundIt != null) { - return foundIt; - } - } - - return null; - } - - private InterceptedElement create(MethodInfo mi, - Set serviceLevelAnnos, - Set interceptorAnnotationTriggers) { - MethodElementInfo elementInfo = createMethodElementInfo(mi, serviceLevelAnnos); - Set applicableTriggers = new LinkedHashSet<>(interceptorAnnotationTriggers); - applicableTriggers.retainAll(elementInfo.annotations() - .stream() - .map(a -> a.typeName()) - .collect(Collectors.toSet())); - return InterceptedElement.builder() - .interceptedTriggerTypeNames(applicableTriggers) - .elementInfo(elementInfo) - .build(); - } - } - - /** - * Create an annotation resolver based on annotation processing. - * - * @param processEnv the processing env - * @return the {@link InterceptorCreatorDefault.AnnotationTypeNameResolver} to use - */ - static AnnotationTypeNameResolver createResolverFromProcessor(ProcessingEnvironment processEnv) { - return new ProcessorResolver(processEnv.getElementUtils()); - } - - /** - * Create an annotation resolver based on reflective processing. - * - * @return the {@link InterceptorCreatorDefault.AnnotationTypeNameResolver} to use - */ - static AnnotationTypeNameResolver createResolverFromReflection() { - return new ReflectionResolver(SCAN.get()); - } - - @Override - public AbstractInterceptorProcessor createInterceptorProcessor(ServiceInfoBasics interceptedService, - InterceptorCreator delegateCreator, - ProcessingEnvironment processEnv) { - Objects.requireNonNull(interceptedService); - Objects.requireNonNull(delegateCreator); - Objects.requireNonNull(processEnv); - - Options.init(processEnv); - ALLOW_LIST.addAll(Options.getOptionStringList(Options.TAG_ALLOW_LISTED_INTERCEPTOR_ANNOTATIONS) - .stream() - .map(TypeName::create) - .toList()); - - return new ProcessorBased(interceptedService, - delegateCreator, - processEnv, - logger()); - } - - - @Override - public InterceptorProcessor createInterceptorProcessor(ServiceInfoBasics interceptedService, - InterceptorCreator delegateCreator) { - Objects.requireNonNull(interceptedService); - Objects.requireNonNull(delegateCreator); - - String resolvedType = interceptedService.serviceTypeName().resolvedName(); - return new ReflectionBased(Objects.requireNonNull(interceptedService), - Objects.requireNonNull(delegateCreator), - Objects.requireNonNull(SCAN.get().getClassInfo(resolvedType)), - logger()); - } - - /** - * Creates the interceptor source code type name given its plan. - * - * @param plan the plan - * @return the interceptor type name - */ - static TypeName createInterceptorSourceTypeName(InterceptionPlan plan) { - String parent = plan.interceptedService().serviceTypeName().resolvedName(); - return toInterceptorTypeName(parent); - } - - /** - * Creates the source code associated with an interception plan. - * - * @param plan the plan - * @return the java source code body - */ - String createInterceptorSourceBody(InterceptionPlan plan) { - TypeName generatorType = TypeName.create(getClass()); - TypeName triggerType = TypeName.create(plan.interceptedService().serviceTypeName().resolvedName()); - - String parent = plan.interceptedService().serviceTypeName().resolvedName(); - TypeName interceptorTypeName = toInterceptorTypeName(parent); - Map subst = new HashMap<>(); - subst.put("packageName", interceptorTypeName.packageName()); - subst.put("className", interceptorTypeName.className()); - subst.put("parent", parent); - subst.put("header", CopyrightHandler.copyright(generatorType, - triggerType, - interceptorTypeName)); - subst.put("generatedanno", templateHelper().generatedStickerFor(generatorType, - triggerType, - interceptorTypeName)); - subst.put("weight", interceptorWeight(plan.interceptedService().declaredWeight())); - subst.put("interceptedmethoddecls", toInterceptedMethodDecls(plan)); - subst.put("interfaces", toInterfacesDecl(plan)); - subst.put("interceptedelements", IdAndToString - .toList(plan.interceptedElements(), InterceptorCreatorDefault::toBody).stream() - .filter(it -> !it.getId().equals(CTOR_ALIAS)) - .collect(Collectors.toList())); - subst.put("ctorinterceptedelements", IdAndToString - .toList(plan.interceptedElements(), InterceptorCreatorDefault::toBody).stream() - .filter(it -> it.getId().equalsIgnoreCase(CTOR_ALIAS)) - .toList()); - subst.put("annotationtriggertypenames", IdAndToString - .toList(plan.annotationTriggerTypeNames(), - typeName -> new IdAndToString(typeName.fqName().replace(".", "_"), - typeName.fqName().replace('$', '.')))); - subst.put("servicelevelannotations", IdAndToString - .toList(plan.serviceLevelAnnotations(), InterceptorCreatorDefault::toDecl)); - String template = templateHelper().safeLoadTemplate( - plan.hasNoArgConstructor() ? NO_ARG_INTERCEPTOR_HBS : INTERFACES_INTERCEPTOR_HBS); - return templateHelper().applySubstitutions(template, subst, true).trim(); - } - - private static List toInterceptedMethodDecls(InterceptionPlan plan) { - List result = new ArrayList<>(); - for (InterceptedElement element : plan.interceptedElements()) { - IdAndToString methodTypedElement = toDecl(element); - result.add(methodTypedElement); - - if (element.elementInfo().elementKind() == io.helidon.inject.api.ElementKind.CONSTRUCTOR) { - continue; - } - - for (ElementInfo param : element.elementInfo().parameterInfo()) { - IdAndToString paramTypedElement = new IdAndToString(element.elementInfo().elementName() - + "__" + param.elementName(), - typeNameElementNameAnnotations(param, false)); - result.add(paramTypedElement); - } - } - return result; - } - - private static String toInterfacesDecl(InterceptionPlan plan) { - return plan.interfaces().stream() - .map(TypeName::name) - .collect(Collectors.joining(", ")); - } - - private static IdAndToString toDecl(InterceptedElement method) { - MethodElementInfo mi = method.elementInfo(); - boolean constructor = mi.elementKind() == io.helidon.inject.api.ElementKind.CONSTRUCTOR; - String name = constructor ? CTOR_ALIAS : mi.elementName(); - String builder = typeNameElementNameAnnotations(mi, constructor); - return new IdAndToString(name, builder); - } - - private static String typeNameElementNameAnnotations(ElementInfo ei, boolean isConstructor) { - StringBuilder builder = new StringBuilder(".typeName(create(" + ei.elementTypeName() + ".class))") - .append("\n\t\t\t.elementTypeKind(TypeValues."); - if (isConstructor) { - builder.append("KIND_CONSTRUCTOR"); - } else { - builder.append("KIND_METHOD"); - } - builder.append(")\n\t\t\t.elementName(").append(CodeGenUtils.elementNameRef(ei.elementName())).append(")"); - TreeSet sortedAnnotations = new TreeSet<>(ei.annotations()); - for (Annotation anno : sortedAnnotations) { - builder.append("\n\t\t\t.addAnnotation(").append(toDecl(anno)).append(")"); - } - return builder.toString(); - } - - private static IdAndToString toDecl(ElementInfo elementInfo) { - String name = elementInfo.elementName(); - return new IdAndToString(name, elementInfo.elementTypeName() + " " + name); - } - - private static IdAndToString toDecl(Annotation anno) { - StringBuilder builder = new StringBuilder("Annotation.create(" + anno.typeName() + ".class"); - Map map = anno.values(); - Object val = anno.objectValue().orElse(null); - if (map != null && !map.isEmpty()) { - builder.append(", Map.of("); - int count = 0; - TreeMap sortedMap = new TreeMap<>(map); - for (Map.Entry e : sortedMap.entrySet()) { - if (count++ > 0) { - builder.append(", "); - } - builder.append("\"") - .append(e.getKey()) - .append("\", ") - .append(mapValueInSources(e.getValue())); - } - builder.append(")"); - } else if (val != null) { - builder.append(", \"") - .append(mapValueInSources(val)) - .append("\""); - } - builder.append(")"); - return new IdAndToString(anno.typeName().name(), builder); - } - - private static String mapValueInSources(Object value) { - if (value instanceof String str) { - return "\"" + str + "\""; - } - if (value instanceof Annotation ann) { - throw new IllegalArgumentException("Cannot process nested annotation in a sample map: " + ann); - } - if (value instanceof List list) { - return "java.util.List.of(" + list.stream() - .map(InterceptorCreatorDefault::mapValueInSources) - .collect(Collectors.joining(", ")) - + ")"; - } - // for primitive types, just use them - return String.valueOf(value); - } - - @SuppressWarnings("checkstyle:OperatorWrap") - private static InterceptedMethodCodeGen toBody(InterceptedElement method) { - MethodElementInfo mi = method.elementInfo(); - String name = (mi.elementKind() == io.helidon.inject.api.ElementKind.CONSTRUCTOR) ? CTOR_ALIAS : mi.elementName(); - StringBuilder builder = new StringBuilder(); - builder.append("public ").append(mi.elementTypeName()).append(" ").append(mi.elementName()).append("("); - String args = mi.parameterInfo().stream() - .map(ElementInfo::elementName) - .collect(Collectors.joining(", ")); - String argDecls = ""; - String objArrayArgs = ""; - String typedElementArgs = ""; - String untypedElementArgs = ""; - boolean hasArgs = (args.length() > 0); - if (hasArgs) { - argDecls = mi.parameterInfo().stream() - .map(InterceptorCreatorDefault::toDecl) - .map(IdAndToString::toString) - .collect(Collectors.joining(", ")); - AtomicInteger count = new AtomicInteger(); - objArrayArgs = mi.parameterInfo().stream() - .map(ElementInfo::elementTypeName) - .map(TypeName::boxed) - .map(typeName -> "(" + typeName + ") " + "args[" + count.getAndIncrement() + "]") - .collect(Collectors.joining(", ")); - - typedElementArgs = mi.parameterInfo().stream() - .map(ei -> "__" + mi.elementName() + "__" + ei.elementName()) - .collect(Collectors.joining(", ")); - - count.set(0); - untypedElementArgs = mi.parameterInfo().stream() - .map(ei -> "args[" + count.getAndIncrement() + "]") - .collect(Collectors.joining(", ")); - } - - boolean hasReturn = !mi.elementTypeName().equals(TypeName.create(void.class)); - builder.append(argDecls); - builder.append(")"); - if (!mi.throwableTypeNames().isEmpty()) { - builder.append(" throws ").append(CommonUtils.toString(mi.throwableTypeNames())); - } - String methodDecl = builder.toString(); - builder.append(" {\n"); - TypeName supplierType = (hasReturn) ? mi.elementTypeName().boxed() : TypeName.create(Void.class); - - String elementArgInfo = ""; - if (hasArgs) { - elementArgInfo = ",\n\t\t\t\tList.of(" + typedElementArgs + ")"; - } - return new InterceptedMethodCodeGen(name, - methodDecl, - true, - hasReturn, - supplierType, - elementArgInfo, - args, - objArrayArgs, - untypedElementArgs, - method.interceptedTriggerTypeNames(), - builder); - } - - private static TypeName toInterceptorTypeName(String serviceTypeName) { - TypeName typeName = TypeName.create(serviceTypeName); - return TypeName.builder() - .packageName(typeName.packageName()) - .className(typeName.className() + INNER_INTERCEPTOR_CLASS_NAME) - .build(); - } - - /** - * Assign a weight slightly higher than the service weight passed in. - * - * @param serviceWeight the service weight, where null defaults to {@link io.helidon.common.Weighted#DEFAULT_WEIGHT}. - * @return the higher weighted value appropriate for interceptors - */ - static double interceptorWeight(Optional serviceWeight) { - double val = serviceWeight.orElse(Weighted.DEFAULT_WEIGHT); - return val + INTERCEPTOR_PRIORITY_DELTA; - } - - - static class InterceptedMethodCodeGen extends IdAndToString { - private final String methodDecl; - private final boolean isOverride; - private final boolean hasReturn; - private final TypeName elementTypeName; - private final String elementArgInfo; - private final String args; - private final String objArrayArgs; - private final String untypedElementArgs; - private final String interceptedTriggerTypeNames; - - InterceptedMethodCodeGen(String id, - String methodDecl, - boolean isOverride, - boolean hasReturn, - TypeName elementTypeName, - String elementArgInfo, - String args, - String objArrayArgs, - String untypedElementArgs, - Collection interceptedTriggerTypeNames, - Object toString) { - super(id, toString); - this.methodDecl = methodDecl; - this.isOverride = isOverride; - this.hasReturn = hasReturn; - this.elementTypeName = elementTypeName; - this.elementArgInfo = elementArgInfo; - this.args = args; - this.objArrayArgs = objArrayArgs; - this.untypedElementArgs = untypedElementArgs; - this.interceptedTriggerTypeNames = CommonUtils.toString(interceptedTriggerTypeNames, - typeName -> typeName.fqName().replace(".", "_"), - null); - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public String getMethodDecl() { - return methodDecl; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public boolean isOverride() { - return isOverride; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public TypeName getElementTypeName() { - return elementTypeName; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public String getElementArgInfo() { - return elementArgInfo; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public String getArgs() { - return args; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public String getObjArrayArgs() { - return objArrayArgs; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public String getUntypedElementArgs() { - return untypedElementArgs; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public boolean getHasReturn() { - return hasReturn; - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public boolean getHasArgs() { - return !args.isEmpty(); - } - - // note: this needs to stay as a public getXXX() method to support Mustache - public String getInterceptedTriggerTypeNames() { - return interceptedTriggerTypeNames; - } - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorProvider.java b/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorProvider.java deleted file mode 100644 index 3952bdbe357..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorProvider.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.ServiceLoader; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.common.LazyValue; -import io.helidon.inject.tools.spi.InterceptorCreator; - -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -/** - * Provides access to the global singleton {@link InterceptorCreator} in use. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Singleton -public class InterceptorCreatorProvider implements Provider { - private static final LazyValue INSTANCE = LazyValue.create(InterceptorCreatorProvider::load); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public InterceptorCreatorProvider() { - } - - private static InterceptorCreator load() { - return HelidonServiceLoader.create( - ServiceLoader.load(InterceptorCreator.class, InterceptorCreator.class.getClassLoader())) - .asList() - .stream() - .findFirst() - .orElseThrow(); - } - - // note that this is guaranteed to succeed since the default implementation is in this module - @Override - public InterceptorCreator get() { - return INSTANCE.get(); - } - - /** - * Returns the global instance that was service loaded. Note that this call is guaranteed to return a result since the - * default implementation is here in this module. - * - * @return the global service instance with the highest weight - */ - public static InterceptorCreator instance() { - return INSTANCE.get(); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorResponseBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorResponseBlueprint.java deleted file mode 100644 index 232fc746ace..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/InterceptorCreatorResponseBlueprint.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.nio.file.Path; -import java.util.Map; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * Response from interception creation. - */ -@Prototype.Blueprint -interface InterceptorCreatorResponseBlueprint { - - /** - * The generated files. - * - * @return the generated files - */ - @Option.Singular - Map generatedFiles(); - - /** - * The interception plans. - * - * @return the interception plans - */ - Map interceptionPlans(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/JavaC.java b/inject/tools/src/main/java/io/helidon/inject/tools/JavaC.java deleted file mode 100644 index 7cda6dde238..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/JavaC.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.File; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; - -/** - * Simple wrapper for compilation, and capturing diagnostic output. - */ -class JavaC { - private static final System.Logger LOGGER = System.getLogger(JavaC.class.getName()); - - private final List classpath = new ArrayList<>(); - private final List sourcepath = new ArrayList<>(); - private final List modulepath = new ArrayList<>(); - private final List commandLineArgs = new ArrayList<>(); - private String source = AbstractCreator.DEFAULT_SOURCE; - private String target = AbstractCreator.DEFAULT_TARGET; - private File outputDirectory; - private System.Logger logger = LOGGER; - private Messager messager; - - /** - * @return The fluent builder for eventual compilation - */ - static Builder builder() { - JavaC compiler = new JavaC(); - return compiler.new Builder(); - } - - /** - * Terminates the builder by triggering compilation. - * - * @param applicationJavaFile the java file to compile - * @return the result of the compilation - */ - Result compile(File applicationJavaFile) { - return new Result(applicationJavaFile); - } - - String toClasspath() { - if (!classpath.isEmpty()) { - return CommonUtils.toPathString(classpath); - } - return null; - } - - String toSourcepath() { - if (!sourcepath.isEmpty()) { - return CommonUtils.toPathString(sourcepath); - } - return null; - } - - String toModulePath() { - if (!modulepath.isEmpty()) { - return CommonUtils.toPathString(modulepath); - } - return null; - } - - - class Builder { - private boolean closed; - - private Builder() { - } - - Builder outputDirectory(File outputDirectory) { - assert (!closed); - JavaC.this.outputDirectory = outputDirectory; - return this; - } - - Builder classpath(List classpath) { - assert (!closed); - JavaC.this.classpath.clear(); - JavaC.this.classpath.addAll(classpath); - return this; - } - - Builder sourcepath(List sourcepath) { - assert (!closed); - JavaC.this.sourcepath.clear(); - JavaC.this.sourcepath.addAll(sourcepath); - return this; - } - - Builder modulepath(List modulepath) { - assert (!closed); - JavaC.this.modulepath.clear(); - JavaC.this.modulepath.addAll(modulepath); - return this; - } - - Builder source(String source) { - assert (!closed); - JavaC.this.source = (source == null) ? AbstractCreator.DEFAULT_SOURCE : source; - return this; - } - - Builder target(String target) { - assert (!closed); - JavaC.this.target = (target == null) ? AbstractCreator.DEFAULT_TARGET : target; - return this; - } - - Builder commandLineArgs(List commandLineArgs) { - assert (!closed); - JavaC.this.commandLineArgs.clear(); - JavaC.this.commandLineArgs.addAll(commandLineArgs); - return this; - } - - Builder logger(System.Logger logger) { - assert (!closed); - JavaC.this.logger = logger; - return this; - } - - Builder messager(Messager messager) { - assert (!closed); - JavaC.this.messager = messager; - return this; - } - - JavaC build() { - assert (outputDirectory == null || outputDirectory.exists()); - closed = true; - return JavaC.this; - } - } - - @SuppressWarnings("rawtypes") - class Result implements DiagnosticListener { - private final List> diagList = new ArrayList<>(); - private boolean isSuccessful = true; - private boolean hasWarnings = false; - - @SuppressWarnings("unchecked") - private Result(File applicationJavaFile) { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - StandardJavaFileManager fileManager = compiler.getStandardFileManager(this, null, null); - - List optionList = new ArrayList<>(); - if (!classpath.isEmpty()) { - optionList.add("-classpath"); - optionList.add(toClasspath()); - } - if (!modulepath.isEmpty()) { - optionList.add("--module-path"); - optionList.add(toModulePath()); - } - if (!sourcepath.isEmpty()) { - optionList.add("--source-path"); - optionList.add(toSourcepath()); - } - if (source != null) { - optionList.add("--source"); - optionList.add(source); - } - if (target != null) { - optionList.add("--target"); - optionList.add(target); - } - optionList.addAll(commandLineArgs); - if (outputDirectory != null) { - optionList.add("-d"); - optionList.add(outputDirectory.getPath()); - } - - List filesToCompile = new ArrayList<>(); - filesToCompile.add(applicationJavaFile); - if (!modulepath.isEmpty()) { - modulepath.forEach(path -> { - File pathToPossibleModuleInfo = new File(path.toFile(), ModuleUtils.REAL_MODULE_INFO_JAVA_NAME); - if (pathToPossibleModuleInfo.exists()) { - filesToCompile.add(pathToPossibleModuleInfo); - } - }); - } - - Iterable compilationUnit = fileManager - .getJavaFileObjectsFromFiles(filesToCompile); - JavaCompiler.CompilationTask task = compiler - .getTask(null, fileManager, this, optionList, null, compilationUnit); - - if (messager != null) { - messager.debug("javac " + CommonUtils.toString(optionList, null, " ") + " " + applicationJavaFile); - } - - Boolean result = task.call(); - // we do it like this to allow for warnings to be treated as errors - if (result != null && !result) { - isSuccessful = false; - } - } - - public boolean isSuccessful() { - return isSuccessful; - } - - @SuppressWarnings("unused") - public boolean hasWarnings() { - return hasWarnings; - } - - public ToolsException maybeGenerateError() { - if (!isSuccessful()) { - return new ToolsException("Compilation error encountered:\n" - + diagList.stream().map(Object::toString).collect(Collectors.joining("\n"))); - } - return null; - } - - @Override - public void report(Diagnostic diagnostic) { - System.Logger.Level level; - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - level = System.Logger.Level.ERROR; - isSuccessful = false; - } else if (Diagnostic.Kind.MANDATORY_WARNING == diagnostic.getKind() - || Diagnostic.Kind.WARNING == diagnostic.getKind()) { - level = System.Logger.Level.WARNING; - hasWarnings = true; - } else { - level = System.Logger.Level.INFO; - } - diagList.add(diagnostic); - - if (messager == null) { - logger.log(level, diagnostic); - return; - } - - String message = diagnostic.toString(); - if (System.Logger.Level.ERROR == level) { - messager.error(message, null); - } else if (System.Logger.Level.WARNING == level) { - messager.debug(message, null); - } else { - messager.debug(message); - } - } - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/Messager.java b/inject/tools/src/main/java/io/helidon/inject/tools/Messager.java deleted file mode 100644 index ebf3691c533..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/Messager.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -/** - * Abstraction for logging messages. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface Messager { - - /** - * Log a debug message. - * - * @param message the message - */ - void debug(String message); - - /** - * Log a debug message. - * - * @param message the message - * @param t throwable - */ - void debug(String message, - Throwable t); - - /** - * Log an info message. - * - * @param message the message - */ - void log(String message); - - /** - * Log a warning. - * - * @param message the message - */ - void warn(String message); - - /** - * Log a warning message. - * - * @param message the message - * @param t throwable - */ - void warn(String message, - Throwable t); - - /** - * Log an error message. - * - * @param message the message - * @param t any throwable - */ - void error(String message, - Throwable t); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/MethodElementInfoBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/MethodElementInfoBlueprint.java deleted file mode 100644 index 27aa8087382..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/MethodElementInfoBlueprint.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; - -import io.helidon.builder.api.Prototype; -import io.helidon.inject.api.ElementInfo; - -/** - * Describes a method element. - */ -@Prototype.Blueprint -interface MethodElementInfoBlueprint extends ElementInfo { - - /** - * The list of "throws" that the method throws. Applies only to - * {@link io.helidon.inject.api.ElementKind#METHOD} element types. - * - * @return the list of throwable types this method may throw - */ - List throwableTypeNames(); - - /** - * Provides information for each parameter to the method. - * - * @return parameter info - */ - List parameterInfo(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleDetailBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleDetailBlueprint.java deleted file mode 100644 index ca90f1f707e..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleDetailBlueprint.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -/** - * The specifics for a single {@link io.helidon.inject.api.ModuleComponent} that was codegen'ed. - * - * @see ActivatorCreatorResponse#moduleDetail - */ -@Prototype.Blueprint -interface ModuleDetailBlueprint { - - /** - *Names of the service provider activators for this module. - * - * @return name of the service provider activators for this module - */ - Set serviceProviderActivatorTypeNames(); - - /** - * The name of this module. - * - * @return name of this module - */ - String moduleName(); - - /** - * The FQN of the module class name. - * - * @return The fqn of the module class name - */ - TypeName moduleTypeName(); - - /** - * The codegen body for the module. - * - * @return body for the module - */ - Optional moduleBody(); - - /** - * The Java 9+ module-info.java contents. - * - * @return contents for module-info body - */ - Optional moduleInfoBody(); - - /** - * The descriptor cooresponding to any {@link #moduleInfoBody()}. - * - * @return descriptor creator - */ - Optional descriptor(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoCreatorRequestBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoCreatorRequestBlueprint.java deleted file mode 100644 index 15d2df34b0c..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoCreatorRequestBlueprint.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Used to represent the parameters that feed into the code generation of a module-info file specifically for Injection in that - * it offers easy ability to add the {@link io.helidon.inject.api.ModuleComponent} as well as optionally the - * {@link io.helidon.inject.api.Application}. - */ -@Prototype.Blueprint -interface ModuleInfoCreatorRequestBlueprint { - - /** - * Optionally, the module name. If not provided then an attempt will be made to calculate the suggested name. - * - * @return module name - */ - Optional name(); - - /** - * The {@link io.helidon.inject.api.ModuleComponent} type name. - * - * @return module type name - */ - TypeName moduleTypeName(); - - /** - * The {@link io.helidon.inject.api.Application} type name. - * - * @return application type name - */ - Optional applicationTypeName(); - - /** - * Set to true if the {@link io.helidon.inject.api.ModuleComponent} should be created. - * - * @return true if the Module should be created - */ - @ConfiguredOption("true") - boolean moduleCreated(); - - /** - * Set to true if the {@link io.helidon.inject.api.Application} should be created. - * - * @return true if the Application should be created - */ - boolean applicationCreated(); - - /** - * The modules required list. - * - * @return modules required - */ - List modulesRequired(); - - /** - * The service type mapping to contracts for that service type. - * - * @return service type mapping to contracts - */ - Map> contracts(); - - /** - * The service type mapping to external contracts for that service type. - * - * @return service type mapping to external contracts - */ - Map> externalContracts(); - - /** - * Optionally, the path for where to access the module-info file. - * - * @return module info path - */ - Optional moduleInfoPath(); - - /** - * The class name prefix for the code generated class. - * - * @return class name prefix - */ - String classPrefixName(); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoDescriptorBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoDescriptorBlueprint.java deleted file mode 100644 index ac8e5cdc148..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoDescriptorBlueprint.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * Provides the basic formation for {@code module-info.java} creation and manipulation. - * - * @see java.lang.module.ModuleDescriptor - */ -@Prototype.Blueprint -@Prototype.CustomMethods(ModuleInfoDescriptorSupport.class) -interface ModuleInfoDescriptorBlueprint { - - /** - * The default module name (i.e., "unnamed"). - */ - String DEFAULT_MODULE_NAME = "unnamed"; - - /** - * The base module-info name. - */ - String MODULE_INFO_NAME = "module-info"; - - /** - * The java module-info name. - */ - String DEFAULT_MODULE_INFO_JAVA_NAME = MODULE_INFO_NAME + ".java"; - - /** - * The module name. - * - * @return the module name - */ - @ConfiguredOption(DEFAULT_MODULE_NAME) - String name(); - - /** - * The template name to apply. The default is {@link TemplateHelper#DEFAULT_TEMPLATE_NAME}. - * - * @return the template name - */ - @ConfiguredOption(TemplateHelper.DEFAULT_TEMPLATE_NAME) - String templateName(); - - /** - * The header (i.e., copyright) comment - will appear at the very start of the output. - * - * @return the header comment - */ - Optional headerComment(); - - /** - * The description comment - will appear directly above the module's {@link #name()}. - * - * @return the description comment - */ - Optional descriptionComment(); - - /** - * The ordering applied. - * - * @return the ordering - */ - @ConfiguredOption("NATURAL") - ModuleInfoOrdering ordering(); - - /** - * The items contained by this module-info. - * - * @return the items - */ - @Option.Singular - List items(); - - /** - * The items that were not handled (due to parsing outages, etc.). - * - * @return the list of unhandled lines - */ - @Option.Singular - List unhandledLines(); - - /** - * Any throwable/error that were encountered during parsing. - * - * @return optionally any error encountered during parsing - */ - Optional error(); - - /** - * Returns {@code true} if last parsing operation was successful (i.e., if there were no instances of - * {@link #unhandledLines()} or {@link #error()}'s encountered). - * - * @return true if any parsing of the given module-info descriptor appears to be full and complete - */ - default boolean handled() { - return error().isEmpty() && unhandledLines().isEmpty(); - } - - /** - * Returns true if the name currently set is the same as the {@link #DEFAULT_MODULE_NAME}. - * - * @return true if the current name is the default name - */ - default boolean isUnnamed() { - return DEFAULT_MODULE_NAME.equals(name()); - } - - /** - * Provides the ability to create a new merged descriptor using this as the basis, and then combining another into it - * in order to create a new descriptor. - * - * @param another the other descriptor to merge - * @return the merged descriptor - */ - @SuppressWarnings("unchecked") - default ModuleInfoDescriptor mergeCreate(ModuleInfoDescriptor another) { - if (another == this) { - throw new IllegalArgumentException("can't merge with self"); - } - - ModuleInfoDescriptor.Builder newOne = ModuleInfoDescriptor.builder((ModuleInfoDescriptor) this); - for (ModuleInfoItem itemThere : another.items()) { - Optional itemHere = first(itemThere); - if (itemHere.isPresent()) { - int index = newOne.items().indexOf(itemHere.get()); - newOne.items().remove(index); - ModuleInfoItem mergedItem = itemHere.get().mergeCreate(itemThere); - newOne.items().add(index, mergedItem); - } else { - newOne.addItem(itemThere); - } - } - - return newOne.build(); - } - - /** - * Saves the descriptor source to the provided path. - * - * @param path the target path - * @throws ToolsException if there is any exception encountered - */ - default void save(Path path) { - try { - Files.writeString(path, contents()); - } catch (IOException e) { - throw new ToolsException("Unable to save: " + path, e); - } - } - - /** - * Retrieves the first item matching the target requested. - * - * @param item the item to find - * @return the item or empty if not found - */ - default Optional first(ModuleInfoItem item) { - return items().stream() - .filter(it -> (item.uses() && it.uses()) - || (item.opens() && it.opens()) - || (item.exports() && it.exports()) - || (item.provides() && it.provides()) - || (item.requires() && it.requires())) - .filter(it -> it.target().equals(item.target())) - .findFirst(); - } - - /** - * Returns the first export found in the module that is unqualified with any extra {@code to} declaration. - * - * @return the first package that is exported from this module, or empty if there are no exports appropriate - */ - default Optional firstUnqualifiedPackageExport() { - return items().stream() - .filter(item -> item.exports() && item.withOrTo().isEmpty()) - .map(ModuleInfoItem::target) - .findFirst(); - } - - /** - * Provides the content of the description appropriate to write out. - * - * @return the contents (source code body) for this descriptor - */ - default String contents() { - return contents(true); - } - - /** - * Provides the content of the description appropriate to write out. - * - * @param wantAnnotation flag determining whether the Generated annotation comment should be present - * @return the contents (source code body) for this descriptor - */ - default String contents(boolean wantAnnotation) { - TemplateHelper helper = TemplateHelper.create(); - - Map subst = new HashMap<>(); - subst.put("name", name()); - List items = items(); - if (!items.isEmpty()) { - if (ModuleInfoOrdering.SORTED == ordering()) { - ArrayList newItems = new ArrayList<>(); - items.forEach(i -> newItems.add(ModuleInfoItem.builder(i).ordering(ModuleInfoOrdering.SORTED).build())); - items = newItems; - items.sort(Comparator.comparing(ModuleInfoItem::target)); - } - subst.put("items", items); - } - if (wantAnnotation) { - TypeName generator = TypeName.create(ModuleInfoDescriptor.class); - subst.put("generatedanno", - (ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS == ordering() || headerComment().isPresent()) - ? null : helper.generatedStickerFor(generator, - generator, - TypeName.create("module-info"))); - } - headerComment().ifPresent(it -> subst.put("header", it)); - descriptionComment().ifPresent(it -> subst.put("description", it)); - subst.put("hasdescription", descriptionComment().isPresent()); - String template = helper.safeLoadTemplate(templateName(), ModuleUtils.SERVICE_PROVIDER_MODULE_INFO_HBS); - String contents = helper.applySubstitutions(template, subst, true); - contents = CommonUtils.trimLines(contents); - if (!wantAnnotation) { - contents = contents.replace("\t", " "); - } - return contents; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoDescriptorSupport.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoDescriptorSupport.java deleted file mode 100644 index 9d680e6ebd2..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoDescriptorSupport.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import io.helidon.builder.api.Prototype; -import io.helidon.common.types.TypeName; - -final class ModuleInfoDescriptorSupport { - private ModuleInfoDescriptorSupport() { - } - - /** - * Loads and creates the {@code module-info} descriptor given its source file location. - * - * @param path the source path location for the module-info descriptor - * @return the module-info descriptor - * @throws ToolsException if there is any exception encountered - */ - @Prototype.FactoryMethod - static ModuleInfoDescriptor create(Path path) { - return create(path, ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS); - } - - /** - * Loads and creates the {@code module-info} descriptor given its source file location and preferred ordering scheme. - * - * @param path the source path location for the module-info descriptor - * @param ordering the ordering to apply - * @return the module-info descriptor - * @throws ToolsException if there is any exception encountered - */ - @Prototype.FactoryMethod - static ModuleInfoDescriptor create(Path path, - ModuleInfoOrdering ordering) { - try { - String moduleInfo = Files.readString(path); - return create(moduleInfo, ordering, false); - } catch (IOException e) { - throw new ToolsException("Unable to load: " + path, e); - } - } - - /** - * Loads and creates the {@code module-info} descriptor given its literal source. - * - * @param moduleInfo the source - * @return the module-info descriptor - * @throws ToolsException if there is any exception encountered - */ - @Prototype.FactoryMethod - static ModuleInfoDescriptor create(String moduleInfo) { - return create(moduleInfo, ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS, false); - } - - /** - * Loads and creates the {@code module-info} descriptor given its literal source and preferred ordering scheme. - * - * @param moduleInfo the source - * @param ordering the ordering to apply - * @param strict when set to true, parsing must pass fully and completely (i.e., {@link ModuleInfoDescriptor#handled()} ()} must be true) - * @return the module-info descriptor - * @throws ToolsException if there is any exception encountered - */ - @Prototype.FactoryMethod - static ModuleInfoDescriptor create(String moduleInfo, - ModuleInfoOrdering ordering, - boolean strict) { - ModuleInfoDescriptor.Builder descriptor = ModuleInfoDescriptor.builder(); - - String clean = moduleInfo; - List comments = null; - if (ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS == ordering) { - comments = new ArrayList<>(); - } else { - clean = moduleInfo.replaceAll("/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/|//.*", ""); - } - - boolean firstLine = true; - Map importAliases = new LinkedHashMap<>(); - String line = null; - try (BufferedReader reader = new BufferedReader(new StringReader(clean))) { - while (null != (line = cleanLine(reader, comments, importAliases))) { - if (firstLine && (comments != null) && comments.size() > 0) { - descriptor.headerComment(String.join("\n", comments)); - } - firstLine = false; - - String[] split = line.split("\\s+"); - if (line.startsWith("module ")) { - descriptor.name(split[1]); - } else if (line.startsWith("requires ")) { - int start = 1; - boolean isStatic = (split[start].equals("static")); - boolean isTransitive = (split[start].equals("transitive")); - if (isStatic || isTransitive) { - start++; - } - for (int i = start; i < split.length; i++) { - descriptor.addItem(requiresModuleName(cleanLine(split[i]), isTransitive, isStatic, - (comments != null) ? comments : List.of())); - } - } else if (line.startsWith("exports ")) { - ModuleInfoItem.Builder exports = ModuleInfoItem.builder() - .exports(true) - .target(resolve(split[1], importAliases)) - .precomments((comments != null) ? comments : List.of()); - for (int i = 2; i < split.length; i++) { - if (!"to".equalsIgnoreCase(split[i])) { - exports.addWithOrTo(resolve(cleanLine(split[i]), importAliases)); - } - } - descriptor.addItem(exports.build()); - } else if (line.startsWith("uses ")) { - ModuleInfoItem.Builder uses = ModuleInfoItem.builder() - .uses(true) - .target(resolve(split[1], importAliases)) - .precomments((comments != null) ? comments : List.of()); - descriptor.addItem(uses.build()); - } else if (line.startsWith("provides ")) { - ModuleInfoItem.Builder provides = ModuleInfoItem.builder() - .provides(true) - .target(resolve(split[1], importAliases)) - .precomments((comments != null) ? comments : List.of()); - if (split.length < 3) { - throw new ToolsException("Unable to process module-info's use of: " + line); - } - if (split[2].equals("with")) { - for (int i = 3; i < split.length; i++) { - provides.addWithOrTo(resolve(cleanLine(split[i]), importAliases)); - } - } - descriptor.addItem(provides.build()); - } else if (line.startsWith("opens ")) { - ModuleInfoItem.Builder opens = ModuleInfoItem.builder() - .opens(true) - .target(resolve(split[1], importAliases)) - .precomments((comments != null) ? comments : List.of()); - if (split.length < 3) { - throw new ToolsException("Unable to process module-info's use of: " + line); - } - if (split[2].equals("to")) { - for (int i = 3; i < split.length; i++) { - opens.addWithOrTo(cleanLine(split[i])); - } - } - descriptor.addItem(opens.build()); - } else if (line.equals("}")) { - break; - } else { - throw new ToolsException("Unable to process module-info's use of: " + line); - } - - if (comments != null) { - comments = new ArrayList<>(); - } - } - } catch (Throwable e) { - ToolsException te; - if (line != null) { - e = new ToolsException("Failed to parse line: " + line, e); - descriptor.addUnhandledLine(line); - } - te = new ToolsException("Unable to load or parse module-info: " + moduleInfo, e); - if (strict) { - throw te; - } - descriptor.error(te); - } - - return descriptor.build(); - } - - /** - * Loads and creates the {@code module-info} descriptor given its source input stream. - * - * @param is the source file input stream - * @return the module-info descriptor - * @throws ToolsException if there is any exception encountered - */ - @Prototype.FactoryMethod - static ModuleInfoDescriptor create(InputStream is) { - return create(is, ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS); - } - - /** - * Loads and creates the {@code module-info} descriptor given its input stream. - * - * @param is the source file location - * @param ordering the ordering to apply - * @return the module-info descriptor - * @throws ToolsException if there is any exception encountered - */ - @Prototype.FactoryMethod - static ModuleInfoDescriptor create(InputStream is, - ModuleInfoOrdering ordering) { - try { - String moduleInfo = new String(is.readAllBytes(), StandardCharsets.UTF_8); - return create(moduleInfo, ordering, false); - } catch (IOException e) { - throw new ToolsException("Unable to load from stream", e); - } - } - - /** - * Creates a new item declaring a {@code requires} on an external module usage from this module descriptor, that is - * extended to use additional item attributes. - * - * @param moduleName the module name to require - * @param isTransitive true if the requires declaration is transitive - * @param isStatic true if the requires declaration is static - * @param comments any comments to ascribe to the item - * @return the item created - */ - private static ModuleInfoItem requiresModuleName(String moduleName, - boolean isTransitive, - boolean isStatic, - List comments) { - return ModuleInfoItem.builder() - .requires(true) - .precomments(comments) - .isTransitiveUsed(isTransitive) - .isStaticUsed(isStatic) - .target(moduleName) - .build(); - } - - private static String cleanLine(String line) { - if (line == null) { - return null; - } - - while (line.endsWith(";") || line.endsWith(",")) { - line = line.substring(0, line.length() - 1).trim(); - } - - if (line.contains("/*") || line.contains("*/")) { - throw new ToolsException("Unable to parse lines that have inner comments: '" + line + "'"); - } - - return line.trim(); - } - - private static String cleanLine(BufferedReader reader, - List preComments, - Map importAliases) throws IOException { - String line = reader.readLine(); - if (line == null) { - return null; - } - - String trimmedline = line.trim(); - if (preComments != null) { - boolean incomment = trimmedline.startsWith("//") || trimmedline.startsWith("/*"); - boolean inempty = trimmedline.isEmpty(); - while (incomment || inempty) { - preComments.add(line); - incomment = incomment && !trimmedline.endsWith("*/") && !trimmedline.startsWith("//"); - - line = reader.readLine(); - if (line == null) { - return null; - } - trimmedline = line.trim(); - - inempty = trimmedline.isEmpty(); - if (!inempty && !incomment) { - incomment = trimmedline.startsWith("//") || trimmedline.startsWith("/*"); - } - } - } - - StringBuilder result = new StringBuilder(trimmedline); - String tmp; - while (!trimmedline.endsWith(";") && !trimmedline.endsWith("}") && !trimmedline.endsWith("{") - && (null != (tmp = reader.readLine()))) { - if (tmp.contains("/*") || tmp.contains("*/") || tmp.contains("//")) { - throw new IOException("Unable to parse line-level comments: '" + line + "'"); - } - tmp = tmp.trim(); - result.append(" ").append(tmp); - if (tmp.endsWith(";") || tmp.endsWith("}") || tmp.endsWith("{")) { - break; - } - } - - line = cleanLine(result.toString()); - if (line.startsWith("import ")) { - String[] split = line.split("\\s+"); - TypeName typeName = TypeName.create(split[split.length - 1]); - importAliases.put(typeName.className(), typeName); - line = cleanLine(reader, preComments, importAliases); - } - return line; - } - - private static String resolve(String name, - Map importAliases) { - TypeName typeName = importAliases.get(name); - return (typeName == null) ? name : typeName.name(); - } -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoItemBlueprint.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoItemBlueprint.java deleted file mode 100644 index d1e53c5bcac..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoItemBlueprint.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; - -import io.helidon.builder.api.Option; -import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.ConfiguredOption; - -/** - * These are the individual items that compose the {@link ModuleInfoDescriptor} builder. - *

- * Note that generally speaking the majority of use cases can use methods from {@link ModuleInfoDescriptor} - * instead of needing to use anything provided here. - */ -@Prototype.Blueprint -interface ModuleInfoItemBlueprint { - - /** - * The comments that proceed the item definition. - * - * @return pre-comments - */ - @Option.Singular - List precomments(); - - /** - * The target class name, package name, or module name this item applies to. - * - * @return target - */ - String target(); - - /** - * Returns true if this is a {@code requires} definition. - * - * @return true if this item is using requires - */ - @ConfiguredOption("false") - boolean requires(); - - /** - * Returns true if this is a {@code uses} definition. - * - * @return true if this item is using requires - */ - @ConfiguredOption("false") - boolean uses(); - - /** - * Returns true if this is using a {@code transitive} definition. - * - * @return true if this item is using transitive - */ - @ConfiguredOption("false") - boolean isTransitiveUsed(); - - /** - * Returns true if this is using a {@code static} definition. - * - * @return true if this item is using static - */ - // see https://github.com/helidon-io/helidon/issues/5440 - @ConfiguredOption("false") - boolean isStaticUsed(); - - /** - * Returns true if this is using a {@code exports} definition. - * - * @return true if this item is using exports - */ - @ConfiguredOption("false") - boolean exports(); - - /** - * Returns true if this is using a {@code open} definition. - * - * @return true if this item is using opens - */ - @ConfiguredOption("false") - boolean opens(); - - /** - * Returns true if this is using a {@code provides} definition. - * - * @return true if this item is using provides - */ - @ConfiguredOption("false") - boolean provides(); - - /** - * Applicable if the target is referencing a list of target class or package names. - * - * @return ordering - */ - Optional ordering(); - - /** - * Any {@code with} or {@code to} definitions. - * - * @return the set of with or to definitions - */ - @Option.Singular - Set withOrTo(); - - /** - * If there is any {@link #ordering()} establish requiring a sort then a new sorted set will be returned. - * - * @return optionally the sorted set, else it is the same as {@link #withOrTo()} - */ - default Set withOrToSorted() { - if (ordering().isPresent() - && ordering().get() == ModuleInfoOrdering.SORTED) { - return new TreeSet<>(withOrTo()); - } - - return withOrTo(); - } - - /** - * Provides the content of the description item appropriate to write out. - * - * @return the contents (source code body) for this descriptor item - */ - default String contents() { - StringBuilder builder = new StringBuilder(); - boolean handled = false; - if (uses()) { - assert (!requires()); - assert (!isTransitiveUsed()); - assert (!isStaticUsed()); - assert (!opens()); - assert (!exports()); - builder.append("uses "); - handled = true; - } - if (provides()) { - assert (!requires()); - assert (!isTransitiveUsed()); - assert (!isStaticUsed()); - assert (!opens()); - assert (!exports()); - if (builder.length() > 0) { - builder.append(target()).append(";"); - } - builder.append("provides "); - if (!withOrTo().isEmpty()) { - builder.append(Objects.requireNonNull(target())); - builder.append(" with ").append(String.join(",\n\t\t\t", withOrToSorted())); - return builder.toString(); - } - handled = true; - } - if (opens()) { - assert (!requires()); - assert (!isTransitiveUsed()); - assert (!isStaticUsed()); - assert (!exports()); - builder.append("opens "); - if (!withOrTo().isEmpty()) { - builder.append(Objects.requireNonNull(target())); - builder.append(" to ").append(String.join(",\n\t\t\t", withOrToSorted())); - return builder.toString(); - } - handled = true; - } - if (requires()) { - assert (!exports()); - assert (!(isTransitiveUsed() && isStaticUsed())); - builder.append("requires "); - if (isTransitiveUsed()) { - builder.append("transitive "); - } else if (isStaticUsed()) { - builder.append("static "); - } - handled = true; - } - if (exports()) { - assert (!isTransitiveUsed()); - assert (!isStaticUsed()); - builder.append("exports "); - if (!withOrTo().isEmpty()) { - builder.append(Objects.requireNonNull(target())); - builder.append(" to ").append(String.join(",\n\t\t\t", withOrToSorted())); - return builder.toString(); - } - handled = true; - } - assert (handled) : target(); - builder.append(target()); - return builder.toString(); - } - - /** - * Provides the ability to create a new merged descriptor item using this as the basis, and then combining another into it - * in order to create a new descriptor item. - * - * @param another the other descriptor item to merge - * @return the merged descriptor - */ - default ModuleInfoItem mergeCreate(ModuleInfoItem another) { - if (another == this) { - return (ModuleInfoItem) this; - } - - if (!Objects.equals(target(), another.target())) { - throw new IllegalArgumentException(); - } - - ModuleInfoItem.Builder newOne = ModuleInfoItem.builder(another); - newOne.requires(requires() || another.requires()); - newOne.uses(uses() || another.uses()); - newOne.isTransitiveUsed(isTransitiveUsed() || another.isTransitiveUsed()); - newOne.isStaticUsed(isStaticUsed() || another.isStaticUsed()); - newOne.exports(exports() || another.exports()); - newOne.opens(opens() || another.opens()); - newOne.provides(opens() || another.provides()); - another.withOrTo().forEach(newOne::addWithOrTo); - return newOne.build(); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoOrdering.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoOrdering.java deleted file mode 100644 index d14f71575f7..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoOrdering.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -/** - * Used to declare the preferred ordering of the items in the module-info. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public enum ModuleInfoOrdering { - /** - * Little or no attempt is made to preserve comments, loaded/created ordering is arranged top-down. - */ - NATURAL, - - /** - * Attempt is preserve comments and natural, loaded/created ordering is arranged top-down. - */ - NATURAL_PRESERVE_COMMENTS, - - /** - * Little or no attempt is made to preserve comments, ordering is arranged sorted by the target class or package. - */ - SORTED -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoUtil.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoUtil.java deleted file mode 100644 index 7059e55e1cc..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoUtil.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Supplier; - -import io.helidon.common.types.TypeName; - -final class ModuleInfoUtil { - private ModuleInfoUtil() { - } - - /** - * Takes a builder, and if the target does not yet exist, will add the new module info item from the supplier. - * - * @param builder the fluent builder - * @param target the target to check for existence for - * @param itemSupplier the item to add which presumably has the same target as above - * @return true if added - */ - static boolean addIfAbsent(ModuleInfoDescriptor.Builder builder, - String target, - Supplier itemSupplier) { - Optional existing = first(builder, target); - if (existing.isEmpty()) { - ModuleInfoItem item = Objects.requireNonNull(itemSupplier.get()); - assert (target.equals(item.target())) : "target mismatch: " + target + " and " + item.target(); - builder.addItem(item); - return true; - } - return false; - } - - /** - * Creates a new item {@code exports} on a package from this module descriptor. - * - * @param pkg the package name exported - * @return the item created - */ - static ModuleInfoItem exportsPackage(String pkg) { - return ModuleInfoItem.builder().exports(true).target(pkg).build(); - } - - /** - * Creates a new item {@code exports} on a package from this module descriptor, along with - * a {@code 'to'} declaration. - * - * @param contract the contract definition being exported - * @param to the to part - * @return the item created - */ - static ModuleInfoItem exportsPackage(String contract, - String to) { - return ModuleInfoItem.builder().exports(true).target(contract).addWithOrTo(to).build(); - } - - /** - * Creates a new item declaring it to provide some contract from this module definition, along with - * a {@code 'with'} declaration. - * - * @param contract the contract definition being provided - * @param with the with part - * @return the item created - */ - static ModuleInfoItem providesContract(String contract, - String with) { - return ModuleInfoItem.builder().provides(true).target(contract).addWithOrTo(with).build(); - } - - /** - * Creates a new item declaring a {@code requires} on an external module usage from this module descriptor. - * - * @param moduleName the module name to require - * @return the item created - */ - static ModuleInfoItem requiresModuleName(String moduleName) { - return ModuleInfoItem.builder().requires(true).target(moduleName).build(); - } - - /** - * Creates a new item declaring a {@code requires} on an external module usage from this module descriptor, that is - * extended to use additional item attributes. - * - * @param moduleName the module name to require - * @param isTransitive true if the requires declaration is transitive - * @param isStatic true if the requires declaration is static - * @param comments any comments to ascribe to the item - * @return the item created - */ - static ModuleInfoItem requiresModuleName(String moduleName, - boolean isTransitive, - boolean isStatic, - List comments) { - return ModuleInfoItem.builder() - .requires(true) - .precomments(comments) - .isTransitiveUsed(isTransitive) - .isStaticUsed(isStatic) - .target(moduleName) - .build(); - } - - /** - * Creates a new item declaring a {@code uses} external contract definition from this module descriptor. - * - * @param externalContract the external contract definition - * @return the item created - */ - static ModuleInfoItem usesExternalContract(Class externalContract) { - return usesExternalContract(TypeName.create(externalContract)); - } - - /** - * Creates a new item declaring a {@code uses} external contract definition from this module descriptor. - * - * @param externalContract the external contract definition - * @return the item created - */ - static ModuleInfoItem usesExternalContract(String externalContract) { - return ModuleInfoItem.builder().uses(true).target(externalContract).build(); - } - - /** - * Creates a new item declaring a {@code uses} external contract definition from this module descriptor. - * - * @param externalContract the external contract definition - * @return the item created - */ - static ModuleInfoItem usesExternalContract(TypeName externalContract) { - return usesExternalContract(externalContract.resolvedName()); - } - - private static Optional first(ModuleInfoDescriptor.BuilderBase builder, String target) { - return builder.items() - .stream() - .filter(it -> it.target().equals(target)) - .findFirst(); - } -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleUtils.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleUtils.java deleted file mode 100644 index bc095118e6e..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleUtils.java +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; -import java.util.Set; -import java.util.Stack; -import java.util.concurrent.atomic.AtomicReference; - -import javax.lang.model.element.TypeElement; - -import io.helidon.common.HelidonServiceLoader; -import io.helidon.common.processor.TypeFactory; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.tools.spi.ModuleComponentNamer; - -import static io.helidon.inject.tools.ModuleInfoDescriptorBlueprint.DEFAULT_MODULE_NAME; - -/** - * Module specific utils. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class ModuleUtils { - /** - * The "real" module-info.java file name. - */ - public static final String REAL_MODULE_INFO_JAVA_NAME = ModuleInfoDescriptorBlueprint.DEFAULT_MODULE_INFO_JAVA_NAME; - /** - * The injection generated (e.g., module-info.java.inject) file name. - */ - public static final String MODULE_INFO_JAVA_NAME = REAL_MODULE_INFO_JAVA_NAME + ".inject"; - /** - * The file name written to ./target/inject/ to track the last package name generated for this application. - * This application package name is what we fall back to for the application name and the module name if not otherwise - * specified directly. - */ - public static final String APPLICATION_PACKAGE_FILE_NAME = "app-package-name.txt"; - static final System.Logger LOGGER = System.getLogger(ModuleUtils.class.getName()); - static final String SERVICE_PROVIDER_MODULE_INFO_HBS = "module-info.hbs"; - static final String SRC_MAIN_JAVA_DIR = "/src/main/java"; - static final String SRC_TEST_JAVA_DIR = "/src/test/java"; - static final ModuleInfoItem MODULE_COMPONENT_MODULE_INFO = ModuleInfoItem.builder() - .provides(true) - .target(ModuleComponent.class.getName()) - .build(); - static final ModuleInfoItem APPLICATION_MODULE_INFO = ModuleInfoItem.builder() - .provides(true) - .target(Application.class.getName()) - .build(); - - private ModuleUtils() { - } - - /** - * Returns the suggested package name to use. - * - * @param typeNames the set of types that are being code generated - * @param defaultPackageName the default package name to use if all options are exhausted - * @param descriptor the module-info descriptor - * @return the suggested package name - */ - public static String toSuggestedGeneratedPackageName(Collection typeNames, - String defaultPackageName, - ModuleInfoDescriptor descriptor) { - Objects.requireNonNull(descriptor); - return innerToSuggestedGeneratedPackageName(descriptor, typeNames, defaultPackageName); - } - - /** - * Returns the suggested package name to use. - * - * @param typeNames the set of types that are being code generated - * @param defaultPackageName the default package name to use if all options are exhausted - * @return the suggested package name - */ - public static String toSuggestedGeneratedPackageName(Collection typeNames, - String defaultPackageName) { - return innerToSuggestedGeneratedPackageName(null, typeNames, defaultPackageName); - } - - static String innerToSuggestedGeneratedPackageName(ModuleInfoDescriptor descriptor, - Collection typeNames, - String defaultPackageName) { - String export = null; - if (descriptor != null) { - Optional provides = descriptor.first(APPLICATION_MODULE_INFO); - if (provides.isEmpty() || provides.get().withOrTo().isEmpty()) { - provides = descriptor.first(MODULE_COMPONENT_MODULE_INFO); - } - if (provides.isEmpty() || provides.get().withOrTo().isEmpty()) { - export = descriptor.firstUnqualifiedPackageExport().orElse(null); - } else { - export = TypeName.create(CommonUtils.first(provides.get().withOrTo(), false)).packageName(); - } - } - - if (export == null && typeNames != null) { - // check for any providers who want to give us a name to use - Optional suggested = toSuggestedPackageNameFromProviders(typeNames); - if (suggested.isPresent()) { - return suggested.get(); - } - - // default to the first one - export = typeNames.stream() - .sorted() - .map(TypeName::packageName) - .findFirst().orElse(null); - } - - return (export != null) ? export : defaultPackageName; - } - - private static Optional toSuggestedPackageNameFromProviders(Collection typeNames) { - List namers = HelidonServiceLoader.create(namerLoader()).asList(); - return namers.stream() - .map(it -> it.suggestedPackageName(typeNames)) - .filter(Optional::isPresent) - .map(Optional::get) - .findFirst(); - } - - private static ServiceLoader namerLoader() { - try { - // note: it is important to use this class' CL since maven will not give us the "right" one. - return ServiceLoader.load( - ModuleComponentNamer.class, ModuleComponentNamer.class.getClassLoader()); - } catch (ServiceConfigurationError e) { - // see issue #6261 - running inside the IDE? - // this version will use the thread ctx classloader - System.getLogger(ModuleComponentNamer.class.getName()).log(System.Logger.Level.WARNING, e.getMessage(), e); - return ServiceLoader.load(ModuleComponentNamer.class); - } - } - - /** - * Common way for naming a module (generally for use by {@link Application} and - * {@link ModuleComponent}). - * - * @param moduleName the module name (from module-info) - * @param typeSuffix "test" for test, or null for normal src classes - * @param defaultName the default name to return if it cannot be determined - * @return the suggested module name or defaultName if it cannot be properly determined - */ - static String toSuggestedModuleName(String moduleName, - String typeSuffix, - String defaultName) { - if (moduleName == null && typeSuffix == null) { - return defaultName; - } - if (moduleName == null) { - moduleName = (defaultName == null) ? DEFAULT_MODULE_NAME : defaultName; - } - String suffix = normalizedModuleNameTypeSuffix(typeSuffix); - return (typeSuffix == null || moduleName.endsWith(suffix)) ? moduleName : moduleName + suffix; - } - - /** - * Returns the module's name. - * - * @param typeSuffix the type suffix. - * @return the module name suffix - */ - static String normalizedModuleNameTypeSuffix(String typeSuffix) { - if (!CommonUtils.hasValue(typeSuffix)) { - return ""; - } - return "/" + typeSuffix; - } - - /** - * Given either a base module name or test module name, will always return the base module name. - * - * @param moduleName the module name (base or test) - * @return the base module name - */ - static String normalizedBaseModuleName(String moduleName) { - if (!CommonUtils.hasValue(moduleName)) { - return moduleName; - } - int pos = moduleName.lastIndexOf("/"); - return (pos >= 0) ? moduleName.substring(0, pos) : moduleName; - } - - /** - * Extract the module name, first attempting the source path (test or main), and if not found using - * the base path, presumably having basePath being a parent in the sourcePath hierarchy. - * - * @param basePath the secondary path to try if module-info was not found in the source path - * @param sourcePath the source path - * @param defaultToUnnamed if true, will return the default name, otherwise empty is returned - * @return the module name suggested to use, most appropriate for the name of {@link - * Application} or {@link ModuleComponent} - */ - public static Optional toSuggestedModuleName(Path basePath, - Path sourcePath, - boolean defaultToUnnamed) { - AtomicReference typeSuffix = new AtomicReference<>(); - ModuleInfoDescriptor descriptor = findModuleInfo(basePath, sourcePath, typeSuffix, null, null) - .orElse(null); - return Optional.ofNullable(toSuggestedModuleName((descriptor != null) ? descriptor.name() : null, typeSuffix.get(), - defaultToUnnamed ? ModuleInfoDescriptor.DEFAULT_MODULE_NAME : null)); - } - - /** - * Attempts to find the descriptor, setting meta-information that is useful for later processing. - * - * @param basePath the base path to start the search - * @param sourcePath the source path, assumed a child of the base path - * @param typeSuffix the holder that will be set with the type suffix observed - * @param moduleInfoPath the holder that will be set with the module info path - * @param srcPath the holder that will be set with the source path - * @return the descriptor, or null if one cannot be found - */ - static Optional findModuleInfo(Path basePath, - Path sourcePath, - AtomicReference typeSuffix, - AtomicReference moduleInfoPath, - AtomicReference srcPath) { - Objects.requireNonNull(basePath); - Objects.requireNonNull(sourcePath); - // if we found a module-info in the source path, then that has to be the module to use - Set moduleInfoPaths = findFile(sourcePath, REAL_MODULE_INFO_JAVA_NAME); - if (1 == moduleInfoPaths.size()) { - return finishModuleInfoDescriptor(moduleInfoPath, srcPath, moduleInfoPaths, REAL_MODULE_INFO_JAVA_NAME); - } - - // if we did not find it, then there is a chance we are in the test directory; try to infer the module name - String suffix = inferSourceOrTest(basePath, sourcePath); - if (typeSuffix != null) { - typeSuffix.set(suffix); - } - if (!basePath.equals(sourcePath)) { - Path parent = sourcePath.getParent(); - moduleInfoPaths = findFile(parent, basePath, REAL_MODULE_INFO_JAVA_NAME); - if (1 == moduleInfoPaths.size()) { - // looks to be a potential test module, get the base name from the source tree... - return finishModuleInfoDescriptor(moduleInfoPath, srcPath, moduleInfoPaths, REAL_MODULE_INFO_JAVA_NAME); - } else if (moduleInfoPaths.size() > 0) { - LOGGER.log(System.Logger.Level.WARNING, "ambiguous which module-info to select: " + moduleInfoPaths); - } - } - - // if we get to here then there was no "real" module-info file found anywhere in the target build directories - // plan b: look for the injection generated files to infer the name - Path parent = sourcePath.getParent(); - if (parent != null) { - String fileName = String.valueOf(sourcePath.getFileName()); - Path scratch = parent.resolve("inject").resolve(fileName); - moduleInfoPaths = findFile(scratch, scratch, MODULE_INFO_JAVA_NAME); - if (1 == moduleInfoPaths.size()) { - // looks to be a potential test module, get the base name from the source tree... - return finishModuleInfoDescriptor(moduleInfoPath, srcPath, moduleInfoPaths, MODULE_INFO_JAVA_NAME); - } - } - - return Optional.empty(); - } - - /** - * Attempts to infer 'test' or base '' given the path. - * - * @param path the path - * @return 'test' or '' (for base non-test) - */ - public static String inferSourceOrTest(Path path) { - Objects.requireNonNull(path); - Path parent = path.getParent(); - if (parent == null) { - return ""; - } - Path gparent = parent.getParent(); - if (gparent == null) { - return ""; - } - return inferSourceOrTest(gparent, path); - } - - /** - * If the relative path contains "/test/" then returns "test" else returns "". - * - * @param basePath the base path to start the search - * @param sourcePath the source path, assumed a child of the base path - * @return 'test' or '' - */ - static String inferSourceOrTest(Path basePath, - Path sourcePath) { - // create a relative path from the two paths - URI relativePath = basePath.toUri().relativize(sourcePath.toUri()); - String path = relativePath.getPath(); - if (!path.startsWith("/")) { - path = "/" + path; - } - if (path.contains("/test/") || path.contains("/generated-test-sources/") || path.contains("/test-classes/")) { - return "test"; - } - - return ""; - } - - /** - * Translates to the source path coordinate given a source file and type name. - * Only available during annotation processing. - * - * @param filePath the source file path - * @param type the type name - * @return the source path, or empty if it cannot be inferred - */ - public static Optional toSourcePath(Path filePath, - TypeElement type) { - TypeName typeName = TypeFactory.createTypeName(type).orElseThrow(); - Path typePath = Paths.get(TypeTools.toFilePath(typeName)); - if (filePath.endsWith(typePath)) { - return Optional.of(filePath.resolveSibling(typePath)); - } - return Optional.empty(); - } - - /** - * Returns the base module path given its source path. - * - * @param sourcePath the source path - * @return the base path - */ - public static Path toBasePath(String sourcePath) { - int pos = sourcePath.lastIndexOf(SRC_MAIN_JAVA_DIR); - if (pos < 0) { - pos = sourcePath.lastIndexOf(SRC_TEST_JAVA_DIR); - } - if (pos < 0) { - throw new ToolsException("Invalid source path: " + sourcePath); - } - Path path = Path.of(sourcePath.substring(0, pos)); - return Objects.requireNonNull(path); - } - - /** - * Returns true if the given module name is unnamed. - * - * @param moduleName the module name to check - * @return true if the provided module name is unnamed - */ - public static boolean isUnnamedModuleName(String moduleName) { - return !CommonUtils.hasValue(moduleName) - || moduleName.equals(DEFAULT_MODULE_NAME) - || moduleName.equals(DEFAULT_MODULE_NAME + "/test"); - } - - /** - * Attempts to load the app package name from what was previously recorded. - * - * @param scratchPath the scratch directory path - * @return the app package name that was loaded - */ - public static Optional loadAppPackageName(Path scratchPath) { - File scratchDir = scratchPath.toFile(); - File packageFileName = new File(scratchDir, APPLICATION_PACKAGE_FILE_NAME); - if (packageFileName.exists()) { - String packageName; - try { - packageName = Files.readString(packageFileName.toPath(), StandardCharsets.UTF_8); - } catch (IOException e) { - throw new ToolsException("Unable to load: " + packageFileName, e); - } - - if (CommonUtils.hasValue(packageName)) { - return Optional.of(packageName); - } - } - return Optional.empty(); - } - - /** - * Persist the package name into scratch for later usage. - * - * @param scratchPath the scratch directory path - * @param packageName the package name - * @throws ToolsException if there are any errors creating or writing the content - */ - public static void saveAppPackageName(Path scratchPath, - String packageName) { - File scratchDir = scratchPath.toFile(); - File packageFileName = new File(scratchDir, APPLICATION_PACKAGE_FILE_NAME); - try { - Files.createDirectories(packageFileName.getParentFile().toPath()); - Files.writeString(packageFileName.toPath(), packageName, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new ToolsException("Unable to save: " + packageFileName, e); - } - } - - private static Optional finishModuleInfoDescriptor(AtomicReference moduleInfoPath, - AtomicReference srcPath, - Set moduleInfoPaths, - String moduleInfoName) { - File moduleInfoFile = new File(CommonUtils.first(moduleInfoPaths, false).toFile(), moduleInfoName); - if (moduleInfoPath != null) { - moduleInfoPath.set(moduleInfoFile); - } - if (srcPath != null) { - srcPath.set(moduleInfoFile.getParentFile()); - } - return Optional.of(ModuleInfoDescriptor.create(moduleInfoFile.toPath())); - } - - private static Set findFile(Path startPath, - Path untilPath, - String fileToFind) { - if (startPath == null || !startPath.toString().contains(untilPath.toString())) { - return Set.of(); - } - - do { - Set set = findFile(startPath, fileToFind); - if (!set.isEmpty()) { - return set; - } - if (startPath.equals(untilPath)) { - break; - } - startPath = startPath.getParent(); - } while (startPath != null); - - return Set.of(); - } - - private static Set findFile(Path target, - String fileToFind) { - Set result = new LinkedHashSet<>(); - - Stack searchStack = new Stack<>(); - searchStack.add(target); - - while (!searchStack.isEmpty()) { - Path cwdPath = searchStack.pop(); - if (!cwdPath.toFile().exists()) { - continue; - } - - try (DirectoryStream stream = Files.newDirectoryStream(cwdPath)) { - for (Path entry : stream) { - if (Files.isDirectory(entry)) { - searchStack.add(entry); - } - - File file = new File(cwdPath.toFile(), fileToFind); - if (file.exists()) { - result.add(cwdPath); - } - } - } catch (Exception ex) { - LOGGER.log(System.Logger.Level.ERROR, "error while processing directory", ex); - } - } - - return result; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/Options.java b/inject/tools/src/main/java/io/helidon/inject/tools/Options.java deleted file mode 100644 index fb7b575ded0..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/Options.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; - -import javax.annotation.processing.ProcessingEnvironment; - -import io.helidon.inject.api.Application; -import io.helidon.inject.api.InjectionServices; - -/** - * Options that can be provided via -A (in annotation processing mode), or via system properties or env properties - * if running normally. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class Options { - - /** - * Tag for putting Injection's annotation processing into debug mode. - */ - public static final String TAG_DEBUG = InjectionServices.TAG_DEBUG; - /** - * Tag to accept this is a preview feature (so no warning is printed). - */ - public static final String TAG_ACCEPT_PREVIEW = "inject.acceptPreview"; - /** - * Treat all super types as a contract for a given service type being added. - */ - public static final String TAG_AUTO_ADD_NON_CONTRACT_INTERFACES = "inject.autoAddNonContractInterfaces"; - /** - * Pre-creates a placeholder for an {@link Application}. - */ - public static final String TAG_APPLICATION_PRE_CREATE = "inject.application.pre.create"; - /** - * Identify the module name being processed or the desired target module name. - */ - public static final String TAG_MODULE_NAME = "modulename"; - /** - * Identify the sidecar (module-info.java.inject) module file name or path. - */ - public static final String TAG_INJECTION_MODULE_NAME = "inject." + TAG_MODULE_NAME; - /** - * Identify whether any application scopes (from ee) is translated to {@link jakarta.inject.Singleton}. - */ - public static final String TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE = "inject.mapApplicationToSingletonScope"; - /** - * Identify whether any unsupported types should trigger annotation processing to keep going (the default is to fail). - */ - public static final String TAG_IGNORE_UNSUPPORTED_ANNOTATIONS = "inject.ignoreUnsupportedAnnotations"; - /** - * Identify invalid usage of the {@code module-info.java} for appropriate Injection references (the default is to fail). - */ - public static final String TAG_IGNORE_MODULE_USAGE = "inject.ignoreModuleUsage"; - /** - * For future use. Should the module-info.java be automatically patched to reflect the DI model. - */ - static final String TAG_AUTO_PATCH_MODULE_INFO = "inject.autoPatchModuleInfo"; - /** - * Identify the additional annotation type names that will trigger interception. - */ - static final String TAG_ALLOW_LISTED_INTERCEPTOR_ANNOTATIONS = "inject.allowListedInterceptorAnnotations"; - - private static final Map OPTS = new HashMap<>(); - - private Options() { - } - - /** - * Initialize (applicable for annotation processing only). - * - * @param processingEnv the processing env - */ - public static void init(ProcessingEnvironment processingEnv) { - Objects.requireNonNull(processingEnv); - if (OPTS.isEmpty()) { - OPTS.put(TAG_DEBUG, - String.valueOf(isOptionEnabled(TAG_DEBUG, processingEnv))); - OPTS.put(TAG_AUTO_ADD_NON_CONTRACT_INTERFACES, - String.valueOf(isOptionEnabled(TAG_AUTO_ADD_NON_CONTRACT_INTERFACES, processingEnv))); - OPTS.put(TAG_APPLICATION_PRE_CREATE, - String.valueOf(isOptionEnabled(TAG_APPLICATION_PRE_CREATE, processingEnv))); - OPTS.put(TAG_AUTO_PATCH_MODULE_INFO, - String.valueOf(isOptionEnabled(TAG_AUTO_PATCH_MODULE_INFO, processingEnv))); - OPTS.put(TAG_MODULE_NAME, - getOption(TAG_MODULE_NAME, null, processingEnv)); - OPTS.put(TAG_INJECTION_MODULE_NAME, - getOption(TAG_INJECTION_MODULE_NAME, null, processingEnv)); - OPTS.put(TAG_ALLOW_LISTED_INTERCEPTOR_ANNOTATIONS, - getOption(TAG_ALLOW_LISTED_INTERCEPTOR_ANNOTATIONS, null, processingEnv)); - OPTS.put(TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE, - getOption(TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE, null, processingEnv)); - OPTS.put(TAG_IGNORE_UNSUPPORTED_ANNOTATIONS, - getOption(TAG_IGNORE_UNSUPPORTED_ANNOTATIONS, null, processingEnv)); - OPTS.put(TAG_IGNORE_MODULE_USAGE, - getOption(TAG_IGNORE_MODULE_USAGE, null, processingEnv)); - OPTS.put(TAG_ACCEPT_PREVIEW, getOption(TAG_ACCEPT_PREVIEW, null, processingEnv)); - } - } - - /** - * Only supports the subset of options that Injection cares about, and should not be generally used for options. - * - * @param option the key (assumed to be meaningful to this class) - * @return true if the option is enabled - */ - public static boolean isOptionEnabled(String option) { - return "true".equals(getOption(option, "")); - } - - /** - * This only supports the subset of options that Injection cares about, and should not be generally used for options. - * - * @param option the key (assumed to be meaningful to this class) - * @return the option value - */ - public static Optional getOption(String option) { - return Optional.ofNullable(getOption(option, null)); - } - - /** - * Returns a non-null list of comma-delimited string value options. - * - * @param option the key (assumed to be meaningful to this class) - * @return the list of string values that were comma-delimited - */ - static List getOptionStringList(String option) { - String result = getOption(option, null); - if (!CommonUtils.hasValue(result)) { - return List.of(); - } - - return CommonUtils.toList(result); - } - - /** - * This only supports the subset of options that Injection cares about, and should not be generally used for options. - * - * @param option the key (assumed to be meaningful to this class) - * @param defaultVal the default value used if the associated value is null. - * @return the option value - */ - private static String getOption(String option, - String defaultVal) { - assert (OPTS.containsKey(option)); - return OPTS.getOrDefault(option, defaultVal); - } - - private static boolean isOptionEnabled(String option, - ProcessingEnvironment processingEnv) { - - String val = processingEnv.getOptions().get(option); - if (val != null) { - return Boolean.parseBoolean(val); - } - - return getOption(option, "", processingEnv).equals("true"); - } - - private static String getOption(String option, - String defaultVal, - ProcessingEnvironment processingEnv) { - String val = processingEnv.getOptions().get(option); - if (val != null) { - return val; - } - - return defaultVal; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/PermittedProviderType.java b/inject/tools/src/main/java/io/helidon/inject/tools/PermittedProviderType.java deleted file mode 100644 index 1f1be58702e..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/PermittedProviderType.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.inject.api.InjectionPointProvider; - -/** - * Defines how the generator should allow the presence of {@link jakarta.inject.Provider}'s or - * {@link InjectionPointProvider}'s. Since providers add a level of non-deterministic behavior - * to the system it is required for the application to explicitly define whether this feature should be permitted. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public enum PermittedProviderType { - - /** - * No provider types are permitted. - */ - NONE, - - /** - * Each individual provider needs to be allow-listed. - */ - NAMED, - - /** - * Allows all/any provider type the system recognizes. - */ - ALL - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ReflectionHandler.java b/inject/tools/src/main/java/io/helidon/inject/tools/ReflectionHandler.java deleted file mode 100644 index 5e7439bb018..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ReflectionHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.inject.api.Resettable; - -import io.github.classgraph.ClassGraph; -import io.github.classgraph.ScanResult; - -/** - * Handles anything involving classpath scanning and introspection. - */ -class ReflectionHandler implements Resettable { - - /** - * The shared instance. - */ - static final ReflectionHandler INSTANCE = new ReflectionHandler(); - - private ClassLoader loader; - private ScanResult scan; - - @Override - public boolean reset(boolean deep) { - if (deep) { - loader = getCurrentLoader(); - scan = new ClassGraph() - .overrideClassLoaders(loader) - .enableAllInfo() - .scan(); - - } else { - loader = null; - scan = null; - } - return true; - } - - private ClassLoader getCurrentLoader() { - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - if (loader == null) { - loader = getClass().getClassLoader(); - } - return loader; - } - - /** - * Lazy scan the classpath. - * - * @return the scan result - */ - ScanResult scan() { - if (scan == null || loader != getCurrentLoader()) { - reset(true); - } - - return scan; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ServicesToProcess.java b/inject/tools/src/main/java/io/helidon/inject/tools/ServicesToProcess.java deleted file mode 100644 index 5629b7f4679..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ServicesToProcess.java +++ /dev/null @@ -1,980 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import javax.annotation.processing.RoundEnvironment; - -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Application; -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.Resettable; -import io.helidon.inject.runtime.Dependencies; - -import static io.helidon.inject.tools.ModuleUtils.APPLICATION_MODULE_INFO; -import static io.helidon.inject.tools.ModuleUtils.MODULE_COMPONENT_MODULE_INFO; - -/** - * Tracks the services to process, and ingests them to build the codegen model. - *

- * The basic flow: - * 'annotation processor(s)' -> ServicesToProcess -> {@link AbstractCreator} derivative. - *

- * Note that the flow might be repeated multiple times since annotation processors by definition are recurrent in - * nature. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class ServicesToProcess implements Resettable { - private static final ServicesToProcess SERVICES = new ServicesToProcess(); - - private static final AtomicInteger RUNNING_PROCESSORS = new AtomicInteger(); - private static final List RUNNABLES_TO_CALL_WHEN_DONE = new ArrayList<>(); - - private final Set servicesTypeNames = new LinkedHashSet<>(); - private final Set servicesTypeNameToCodeGen = new LinkedHashSet<>(); - private final Set requiredModules = new TreeSet<>(); - private final Map> servicesToContracts = new LinkedHashMap<>(); - private final Map> servicesToExternalContracts = new LinkedHashMap<>(); - private final Map servicesToLockParentServiceTypeName = new LinkedHashMap<>(); - private final Map servicesToParentServiceTypeNames = new LinkedHashMap<>(); - private final Map servicesToActivatorGenericDecl = new LinkedHashMap<>(); - private final Map servicesToAccess = new LinkedHashMap<>(); - private final Map servicesToIsAbstract = new LinkedHashMap<>(); - private final Map servicesToDependencies = new LinkedHashMap<>(); - private final Map servicesToPreDestroyMethod = new LinkedHashMap<>(); - private final Map servicesToPostConstructMethod = new LinkedHashMap<>(); - private final Map servicesToWeightedPriority = new LinkedHashMap<>(); - private final Map servicesToRunLevel = new LinkedHashMap<>(); - private final Map> servicesToScopeTypeNames = new LinkedHashMap<>(); - private final Map> servicesToQualifiers = new LinkedHashMap<>(); - private final Map> servicesToProviderFor = new LinkedHashMap<>(); - private final Map interceptorPlanFor = new LinkedHashMap<>(); - private final Map> extraCodeGen = new LinkedHashMap<>(); - private final Map> extraActivatorClassComments = new LinkedHashMap<>(); - private final Map> serviceTypeHierarchy = new LinkedHashMap<>(); - private final Map servicesToDefaultConstructor = new LinkedHashMap<>(); - - private Path lastKnownSourcePathBeingProcessed; - private String lastKnownTypeSuffix; - private String moduleName; - private String lastKnownModuleName; - private Path lastKnownModuleInfoFilePath; - private ModuleInfoDescriptor lastKnownModuleInfoDescriptor; - private Path lastGeneratedModuleInfoFilePath; - private ModuleInfoDescriptor lastGeneratedModuleInfoDescriptor; - private String lastGeneratedPackageName; - - private ServicesToProcess() { - } - - /** - * The current services to process instance. - * - * @return the current services to process instance - */ - public static ServicesToProcess servicesInstance() { - return SERVICES; - } - - /** - * Creates a new instance, apart from the current global singleton instance exposed from {@link #servicesInstance()}. - * - * @return the new instance - * @see #servicesInstance() - */ - public static ServicesToProcess create() { - return new ServicesToProcess(); - } - - /** - * Called to signal the beginning of an annotation processing phase. - * - * @param processor the processor running - * @param annotations the annotations being processed - * @param roundEnv the round env - */ - public static void onBeginProcessing(Messager processor, - Set annotations, - RoundEnvironment roundEnv) { - boolean reallyStarted = !annotations.isEmpty(); - if (reallyStarted && !roundEnv.processingOver()) { - RUNNING_PROCESSORS.incrementAndGet(); - } - processor.debug(processor.getClass() - .getSimpleName() + " processing " + annotations + "; really-started=" + reallyStarted); - } - - /** - * Called to add a runnable to call when done with all annotation processing. - * - * @param runnable the runnable to call - */ - public static void addOnDoneRunnable(Runnable runnable) { - RUNNABLES_TO_CALL_WHEN_DONE.add(runnable); - } - - /** - * Called to signal the end of an annotation processing phase. - * - * @param processor the processor running - * @param annotations the annotations being processed - * @param roundEnv the round env - */ - public static void onEndProcessing(Messager processor, - Set annotations, - RoundEnvironment roundEnv) { - boolean done = annotations.isEmpty(); - if (done && roundEnv.processingOver()) { - RUNNING_PROCESSORS.decrementAndGet(); - } - processor.debug(processor.getClass().getSimpleName() + " finished processing; done-done=" + done); - - if (done && RUNNING_PROCESSORS.get() == 0) { - // perform module analysis to ensure the proper definitions are specified for modules and applications - ServicesToProcess.servicesInstance().performModuleUsageValidation(processor); - } - - if (done) { - RUNNABLES_TO_CALL_WHEN_DONE.forEach(Runnable::run); - RUNNABLES_TO_CALL_WHEN_DONE.clear(); - } - } - - @Override - public boolean reset(boolean ignoredDeep) { - servicesTypeNames.clear(); - servicesTypeNameToCodeGen.clear(); - requiredModules.clear(); - servicesToContracts.clear(); - servicesToExternalContracts.clear(); - // we intentionally except parent service type names from being cleared - we need to remember this fact! - // if (false) { - // servicesToLockParentServiceTypeName.clear(); - // servicesToParentServiceTypeNames.clear(); - // servicesToActivatorGenericDecl.clear(); - // } - servicesToAccess.clear(); - servicesToIsAbstract.clear(); - servicesToDependencies.clear(); - servicesToPreDestroyMethod.clear(); - servicesToPostConstructMethod.clear(); - servicesToWeightedPriority.clear(); - servicesToRunLevel.clear(); - servicesToScopeTypeNames.clear(); - servicesToQualifiers.clear(); - servicesToProviderFor.clear(); - interceptorPlanFor.clear(); - serviceTypeHierarchy.clear(); - extraCodeGen.clear(); - extraActivatorClassComments.clear(); - return true; - } - - /** - * Introduce a new service type name to be added. - * - * @param serviceTypeName the service type name - */ - void addServiceTypeName(TypeName serviceTypeName) { - servicesTypeNames.add(Objects.requireNonNull(serviceTypeName)); - } - - /** - * Introduce the parent superclass for a given service type name. - * - * @param serviceTypeName the service type name - * @param parentServiceTypeName the parent for this service type name - * @return flag indicating whether the parent was accepted - */ - public boolean addParentServiceType(TypeName serviceTypeName, - TypeName parentServiceTypeName) { - return addParentServiceType(serviceTypeName, parentServiceTypeName, Optional.empty()); - } - - /** - * Introduce the parent superclass for a given service type name. - * - * @param serviceTypeName the service type name - * @param parentServiceTypeName the parent for this service type name - * @param lockParent flag indicating whether the parent should be locked - * @return flag indicating whether the parent was accepted - */ - public boolean addParentServiceType(TypeName serviceTypeName, - TypeName parentServiceTypeName, - Optional lockParent) { - if (parentServiceTypeName == null) { - return false; - } - - Boolean locked = servicesToLockParentServiceTypeName.get(serviceTypeName); - if (locked != null) { - if (locked) { - TypeName lockedParentType = servicesToParentServiceTypeNames.get(serviceTypeName); - return parentServiceTypeName.equals(lockedParentType); - } else { - servicesToLockParentServiceTypeName.put(serviceTypeName, lockParent.orElse(null)); - } - } - - addServiceTypeName(serviceTypeName); - servicesToParentServiceTypeNames.put(serviceTypeName, parentServiceTypeName); - lockParent.ifPresent(aBoolean -> servicesToLockParentServiceTypeName.put(serviceTypeName, aBoolean)); - - return true; - } - - /** - * @return the map of service type names to each respective super class / parent types - */ - Map parentServiceTypes() { - return Map.copyOf(servicesToParentServiceTypeNames); - } - - /** - * Introduce the activator generic portion of the declaration (e.g., the "CB extends MySingletonConfig" portion of - * {@code MyService$$injectionActivator}). - * - * @param serviceTypeName the service type name - * @param activatorGenericDecl the generics portion of the class decl - */ - public void addActivatorGenericDecl(TypeName serviceTypeName, - String activatorGenericDecl) { - addServiceTypeName(serviceTypeName); - Object prev = servicesToActivatorGenericDecl.put(serviceTypeName, activatorGenericDecl); - assert (prev == null || Objects.equals(prev, activatorGenericDecl)); - } - - /** - * @return the map of service type names to activator generic declarations - */ - Map activatorGenericDecls() { - return Map.copyOf(servicesToActivatorGenericDecl); - } - - /** - * Introduce the parent superclass for a given service type name. - * - * @param serviceTypeName the service type name - * @param access the access level for the service type name - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addAccessLevel(TypeName serviceTypeName, - AccessModifier access) { - Objects.requireNonNull(serviceTypeName); - Objects.requireNonNull(access); - addServiceTypeName(serviceTypeName); - Object prev = servicesToAccess.put(serviceTypeName, access); - if (prev != null && !access.equals(prev)) { - throw new IllegalStateException("Can only support one access level for " + serviceTypeName); - } - } - - /** - * @return the map of service type names to each respective access level - */ - Map accessLevels() { - return servicesToAccess; - } - - /** - * Introduce the flag whether the given service type name is abstract (i.e., interface or abstract) and not concrete. - * - * @param serviceTypeName the service type name - * @param isAbstract whether the service type name is abstract (i.e., interface or abstract) - */ - public void addIsAbstract(TypeName serviceTypeName, - boolean isAbstract) { - addServiceTypeName(serviceTypeName); - servicesToIsAbstract.put(serviceTypeName, isAbstract); - } - - /** - * @return the map of service type names to whether they are abstract. If not found then assume concrete - */ - Map isAbstractMap() { - return servicesToIsAbstract; - } - - /** - * @return the map of service type names to the super class hierarchy - */ - Map> serviceTypeToHierarchy() { - return serviceTypeHierarchy; - } - - /** - * Introduce the parent superclass for a given service type name. - * - * @param serviceTypeName the service type name - * @param serviceTypeHierarchy the list of superclasses (where this service type is the last in the list) - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addServiceTypeHierarchy(TypeName serviceTypeName, - List serviceTypeHierarchy) { - addServiceTypeName(serviceTypeName); - if (serviceTypeHierarchy != null) { - Object prev = this.serviceTypeHierarchy.put(serviceTypeName, serviceTypeHierarchy); - if (prev != null && !serviceTypeHierarchy.equals(prev)) { - throw new IllegalStateException("Can only support one hierarchy for " + serviceTypeName); - } - } - } - - /** - * Checks whether the service type has an established super class hierarchy set. - * - * @param serviceTypeName the service type name - * @return true if the hierarchy is known for this service type - */ - public boolean hasHierarchyFor(TypeName serviceTypeName) { - Collection coll = serviceTypeHierarchy.get(serviceTypeName); - return (coll != null); - } - - /** - * Checks whether the service type has an established set of contracts that are known for it. - * - * @param serviceTypeName the service type name - * @return true if contracts are known about this service type - */ - public boolean hasContractsFor(TypeName serviceTypeName) { - Collection coll = servicesToContracts.get(serviceTypeName); - if (coll != null) { - return true; - } - - coll = servicesToExternalContracts.get(serviceTypeName); - if (coll != null) { - return true; - } - - coll = servicesToProviderFor.get(serviceTypeName); - return (coll != null); - } - - /** - * Checks whether the service type has been evaluated for an interceptor plan. - * - * @param serviceTypeName the service type name - * @return true if this service type has already been considered for interceptors - */ - public boolean hasVisitedInterceptorPlanFor(TypeName serviceTypeName) { - return interceptorPlanFor.containsKey(serviceTypeName); - } - - /** - * Sets the {@link InterceptionPlan} for the given service type. - * - * @param serviceTypeName the service type name - * @param plan the interceptor plan - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addInterceptorPlanFor(TypeName serviceTypeName, - Optional plan) { - Object prev = interceptorPlanFor.put(serviceTypeName, plan.orElse(null)); - if (prev != null && plan.isPresent()) { - throw new IllegalStateException("Should only set interception plan once for: " + serviceTypeName); - } - } - - /** - * The interception plan for each service type that has a non-null interception plan. - * - * @return the interception plan for each service type - */ - public Map interceptorPlans() { - return interceptorPlanFor.entrySet().stream() - .filter(e -> e.getValue() != null) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b, TreeMap::new)); - } - - /** - * Clears out just the interceptor plans. - */ - public void clearInterceptorPlans() { - interceptorPlanFor.clear(); - } - - /** - * @return the extra code gen to add for each service type - */ - Map> extraCodeGen() { - return extraCodeGen; - } - - /** - * Adds extra code gen per service type. - * - * @param serviceTypeName the service type name - * @param codeGen the extra code gen to tack onto the activator implementation - */ - public void addExtraCodeGen(TypeName serviceTypeName, - String codeGen) { - Objects.requireNonNull(codeGen); - extraCodeGen.compute(serviceTypeName, (key, val) -> { - if (val == null) { - val = new ArrayList<>(); - } - val.add(codeGen); - return val; - }); - } - - /** - * @return the extra activator class level comments for code generated types - */ - Map> extraActivatorClassComments() { - return extraActivatorClassComments; - } - - /** - * Adds extra cactivator class level comments. - * - * @param serviceTypeName the service type name - * @param codeGen the extra comments tack onto the activator implementation - */ - public void addExtraActivatorClassComments(TypeName serviceTypeName, - String codeGen) { - Objects.requireNonNull(codeGen); - extraActivatorClassComments.compute(serviceTypeName, (key, val) -> { - if (val == null) { - val = new ArrayList<>(); - } - val.add(codeGen); - return val; - }); - } - - /** - * Introduces a contract associated with a service type. - * - * @param serviceTypeName the service type name - * @param contractTypeName the contract type name - * @param isExternal whether the contract is external - */ - public void addTypeForContract(TypeName serviceTypeName, - TypeName contractTypeName, - boolean isExternal) { - if (serviceTypeName.equals(contractTypeName)) { - return; - } - - addServiceTypeName(serviceTypeName); - - servicesToContracts.compute(serviceTypeName, (key, val) -> { - if (val == null) { - val = new TreeSet<>(); - } - val.add(contractTypeName); - return val; - }); - - if (isExternal) { - servicesToExternalContracts.compute(serviceTypeName, (key, val) -> { - if (val == null) { - val = new TreeSet<>(); - } - val.add(contractTypeName); - return val; - }); - } - } - - /** - * Introduces a new set of dependencies to the model. - * - * @param dependencies the dependencies - */ - public void addDependencies(DependenciesInfo dependencies) { - TypeName serviceTypeName = dependencies.fromServiceTypeName().orElseThrow(); - addServiceTypeName(serviceTypeName); - DependenciesInfo prevDependencies = servicesToDependencies.get(serviceTypeName); - if (prevDependencies != null) { - dependencies = Dependencies.combine(prevDependencies, dependencies); - } - servicesToDependencies.put(serviceTypeName, dependencies); - } - - /** - * Introduces a {@link jakarta.annotation.PreDestroy} method to the model for a given service type. - * - * @param serviceTypeName the service type name - * @param preDestroyMethodName the method name - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addPreDestroyMethod(TypeName serviceTypeName, - String preDestroyMethodName) { - addServiceTypeName(serviceTypeName); - Object prev = servicesToPreDestroyMethod.put(serviceTypeName, preDestroyMethodName); - if (prev != null) { - throw new IllegalStateException("Can only support one PreDestroy method for " + serviceTypeName); - } - } - - /** - * Introduces a {@link jakarta.annotation.PostConstruct} method to the model for a given service type. - * - * @param serviceTypeName the service type name - * @param postConstructMethodName the method name - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addPostConstructMethod(TypeName serviceTypeName, - String postConstructMethodName) { - addServiceTypeName(serviceTypeName); - Object prev = servicesToPostConstructMethod.put(serviceTypeName, postConstructMethodName); - if (prev != null) { - throw new IllegalStateException("Can only support one PostConstruct method for " + serviceTypeName); - } - } - - /** - * Sets the weight of a service type. - * - * @param serviceTypeName the service type name - * @param weight the weight priority - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addDeclaredWeight(TypeName serviceTypeName, - Double weight) { - addServiceTypeName(serviceTypeName); - Object prev = servicesToWeightedPriority.put(serviceTypeName, weight); - if (prev != null) { - throw new IllegalStateException("Can only support one weighted priority for " + serviceTypeName); - } - } - - /** - * Sets the run level for a service type name. - * - * @param serviceTypeName the service type name - * @param runLevel its run level - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addDeclaredRunLevel(TypeName serviceTypeName, - Integer runLevel) { - addServiceTypeName(serviceTypeName); - Object prev = servicesToRunLevel.put(serviceTypeName, runLevel); - if (prev != null) { - throw new IllegalStateException("Can only support one RunLevel for " + serviceTypeName); - } - } - - /** - * Adds a scope type name for a service type name. - * - * @param serviceTypeName the service type name - * @param scopeTypeName its scope type name - */ - public void addScopeTypeName(TypeName serviceTypeName, - TypeName scopeTypeName) { - Objects.requireNonNull(scopeTypeName); - addServiceTypeName(serviceTypeName); - - servicesToScopeTypeNames.compute(serviceTypeName, (k, v) -> { - if (v == null) { - v = new LinkedHashSet<>(); - } - v.add(scopeTypeName); - return v; - }); - } - - /** - * Establishes the fact that a given service type is a {@link jakarta.inject.Provider} type for the given provided types. - * - * @param serviceTypeName the service type name - * @param providerFor the types that it provides - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addProviderFor(TypeName serviceTypeName, - Set providerFor) { - addServiceTypeName(serviceTypeName); - Object prev = servicesToProviderFor.put(serviceTypeName, providerFor); - if (prev != null && !prev.equals(providerFor)) { - throw new IllegalStateException("Can only support setting isProvider once for " + serviceTypeName); - } - } - - /** - * Sets the qualifiers associated with a service type. - * - * @param serviceTypeName the service type name - * @param qualifiers its qualifiers - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public void addQualifiers(TypeName serviceTypeName, - Set qualifiers) { - addServiceTypeName(serviceTypeName); - Object prev = servicesToQualifiers.put(serviceTypeName, qualifiers); - if (prev != null) { - throw new IllegalStateException("Can only support setting qualifiers once for " + serviceTypeName - + "; prev = " + prev + " and new = " + qualifiers); - } - } - - /** - * Fetches the set of known service type names being processed in this batch. - * - * @return the list of known service type names being processed - */ - public List serviceTypeNames() { - ArrayList result = new ArrayList<>(servicesTypeNames); - Collections.sort(result); - return result; - } - - /** - * Fetches the set of known service type names being code generated in this batch. - * - * @return the list of known service type names being code generated - */ - public List generatedServiceTypeNames() { - ArrayList result = new ArrayList<>(servicesTypeNameToCodeGen); - Collections.sort(result); - return result; - } - - /** - * Sets the service type names being code generated in this batch. - * - * @param coll the collection of services to be code generated - */ - public void generatedServiceTypeNames(Collection coll) { - this.servicesTypeNameToCodeGen.clear(); - this.servicesTypeNameToCodeGen.addAll(coll); - } - - /** - * @return fetches the map of service types to their set of contracts for that service type - */ - Map> contracts() { - return new TreeMap<>(servicesToContracts); - } - - /** - * @return fetches the map of service types to their set of contracts for that service type - */ - Map> externalContracts() { - return new TreeMap<>(servicesToExternalContracts); - } - - /** - * @return fetches the map of service types to their injection point dependencies - */ - Map injectionPointDependencies() { - return new TreeMap<>(servicesToDependencies); - } - - /** - * @return fetches the map of service types to their post construct methods - */ - Map postConstructMethodNames() { - return new TreeMap<>(servicesToPostConstructMethod); - } - - /** - * @return fetches the map of service types to their pre destroy methods - */ - Map preDestroyMethodNames() { - return new TreeMap<>(servicesToPreDestroyMethod); - } - - Map defaultConstructors() { - return new TreeMap<>(servicesToDefaultConstructor); - } - - /** - * Fetches the map of service types to their priorities. - * - * @return the map of service types to their priorities - */ - public Map weightedPriorities() { - return new TreeMap<>(servicesToWeightedPriority); - } - - /** - * Fetches the map of service types to their run levels. - * - * @return the map of service types to their run levels - */ - public Map runLevels() { - return new TreeMap<>(servicesToRunLevel); - } - - /** - * Fetches the map of service types to their scope type names. - * - * @return the map of service types to their scope type names - */ - public Map> scopeTypeNames() { - return new TreeMap<>(servicesToScopeTypeNames); - } - - /** - * @return fetches the map of service types to the set of services they provide - */ - Map> providerForTypeNames() { - return new TreeMap<>(servicesToProviderFor); - } - - /** - * @return fetches the map of service types to the set of qualifiers associated with each - */ - Map> qualifiers() { - return new TreeMap<>(servicesToQualifiers); - } - - /** - * Introduces the need for external modules. - * - * @param serviceTypeName the service type name - * @param moduleNames the required module names to support known external contracts - */ - public void addExternalRequiredModules(TypeName serviceTypeName, - Collection moduleNames) { - if (moduleNames != null) { - requiredModules.addAll(moduleNames); - } - } - - /** - * @return the set of required (external) module names - */ - Set requiredModules() { - return new TreeSet<>(requiredModules); - } - - /** - * Sets this module name. - * - * @param moduleName the module name - */ - public void moduleName(String moduleName) { - this.moduleName = moduleName; - this.lastKnownModuleName = moduleName; - } - - /** - * Clears the module name. - */ - public void clearModuleName() { - this.moduleName = null; - } - - /** - * This module name. - * - * @return this module name - */ - public String moduleName() { - return moduleName; - } - - /** - * The last known descriptor being processed. - * - * @param descriptor the descriptor - */ - public void lastKnownModuleInfoDescriptor(ModuleInfoDescriptor descriptor) { - this.lastKnownModuleInfoDescriptor = descriptor; - if (descriptor != null) { - moduleName(descriptor.name()); - } - } - - /** - * @return fetches the last known module info descriptor - */ - ModuleInfoDescriptor lastKnownModuleInfoDescriptor() { - return lastKnownModuleInfoDescriptor; - } - - /** - * The last known file path location for the module-info descriptor being processed. - * - * @param lastKnownModuleInfoFile the file path location for the descriptor - */ - public void lastKnownModuleInfoFilePath(Path lastKnownModuleInfoFile) { - this.lastKnownModuleInfoFilePath = lastKnownModuleInfoFile; - } - - /** - * @return fetches the last known module info file path - */ - Path lastKnownModuleInfoFilePath() { - return lastKnownModuleInfoFilePath; - } - - /** - * @return fetches the last generated module descriptor location - */ - Path lastGeneratedModuleInfoFilePath() { - return lastGeneratedModuleInfoFilePath; - } - - /** - * Sets the last known source path being processed. - * - * @param lastKnownSourcePathBeingProcessed the last source path being processed - */ - public void lastKnownSourcePathBeingProcessed(Path lastKnownSourcePathBeingProcessed) { - this.lastKnownSourcePathBeingProcessed = lastKnownSourcePathBeingProcessed; - } - - /** - * Sets the last known type suffix (e.g., "test"). - * - * @param typeSuffix the optional type suffix - */ - public void lastKnownTypeSuffix(String typeSuffix) { - this.lastKnownTypeSuffix = typeSuffix; - } - - /** - * @return fetches the last known type suffix - */ - String lastKnownTypeSuffix() { - return lastKnownTypeSuffix; - } - - /** - * Sets the last generated package name. - * - * @param lastGeneratedPackageName the package name - */ - public void lastGeneratedPackageName(String lastGeneratedPackageName) { - this.lastGeneratedPackageName = lastGeneratedPackageName; - } - - /** - * Fetches the last generated package name. - */ - String lastGeneratedPackageName() { - return lastGeneratedPackageName; - } - - /** - * Attempts to determine the generated module name based upon the batch of services being processed. - */ - String determineGeneratedModuleName() { - String moduleName = moduleName(); - moduleName = ModuleUtils.toSuggestedModuleName(moduleName, - lastKnownTypeSuffix(), - ModuleInfoDescriptor.DEFAULT_MODULE_NAME); - return moduleName; - } - - /** - * Attempts to determine the generated package name based upon the batch of services being processed. - */ - String determineGeneratedPackageName() { - String export = lastGeneratedPackageName(); - if (export != null) { - return export; - } - - ModuleInfoDescriptor descriptor = lastKnownModuleInfoDescriptor(); - String packageName = ModuleUtils.innerToSuggestedGeneratedPackageName(descriptor, serviceTypeNames(), "inject"); - return Objects.requireNonNull(packageName); - } - - /** - * Use a custom default constructor code. - * - * @param serviceType type of service - * @param constructor constructor generated code - */ - public void defaultConstructor(TypeName serviceType, String constructor) { - this.servicesToDefaultConstructor.put(serviceType, constructor); - } - - /** - * If we made it here we know that Injection annotation processing was used. If there is a module-info in use and services where - * defined during processing, then we should have a module created and optionally and application. If so then we should - * validate the integrity of the user's module-info.java for the {@link ModuleComponent} and - * {@link Application} definitions - unless the user opted out of this check with the - * {@link Options#TAG_IGNORE_MODULE_USAGE} option. - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - private void performModuleUsageValidation(Messager processor) { - if (lastKnownModuleInfoFilePath != null && lastKnownModuleInfoDescriptor == null) { - throw new IllegalStateException("Expected to have a module-info.java"); - } - - if (lastKnownModuleInfoDescriptor == null) { - return; - } - - boolean wasModuleDefined = !servicesTypeNames.isEmpty() || contracts().values().stream() - .flatMap(Collection::stream) - .anyMatch(it -> it.name().equals(ModuleComponent.class.getName())); - boolean wasApplicationDefined = contracts().values().stream() - .flatMap(Collection::stream) - .anyMatch(it -> it.name().equals(Application.class.getName())); - - boolean shouldWarnOnly = Options.isOptionEnabled(Options.TAG_IGNORE_MODULE_USAGE); - String message = ". Use -A" + Options.TAG_IGNORE_MODULE_USAGE + "=true to ignore."; - - if (wasModuleDefined) { - Optional moduleInfoItem = lastKnownModuleInfoDescriptor.first(MODULE_COMPONENT_MODULE_INFO); - if (moduleInfoItem.isEmpty() || !moduleInfoItem.get().provides()) { - IllegalStateException te = new IllegalStateException("Expected to have a 'provides " - + ModuleComponent.class.getName() - + " with ... ' entry in " - + lastKnownModuleInfoFilePath + message); - if (shouldWarnOnly) { - processor.warn(te.getMessage(), te); - } else { - processor.error(te.getMessage(), te); - } - } - } - - if (wasApplicationDefined) { - Optional moduleInfoItem = lastKnownModuleInfoDescriptor.first(APPLICATION_MODULE_INFO); - if (moduleInfoItem.isEmpty() || !moduleInfoItem.get().provides()) { - ToolsException te = new ToolsException("Expected to have a 'provides " + Application.class.getName() - + " with ... ' entry in " + lastKnownModuleInfoFilePath + message); - if (shouldWarnOnly) { - processor.warn(te.getMessage(), te); - } else { - processor.error(te.getMessage(), te); - } - } - } - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/TemplateHelper.java b/inject/tools/src/main/java/io/helidon/inject/tools/TemplateHelper.java deleted file mode 100644 index aafcea17d51..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/TemplateHelper.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; - -import io.helidon.common.processor.GeneratedAnnotationHandler; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServicesConfig; - -import com.github.jknack.handlebars.Handlebars; -import com.github.jknack.handlebars.TagType; -import com.github.jknack.handlebars.Template; - -/** - * Helper tools for dealing with Injection-related Handlebar templates. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class TemplateHelper { - /** - * The tag that us used to represent the template name to use. - */ - public static final String TAG_TEMPLATE_NAME = "io.helidon.inject.template.name"; - - /** - * The default template name to use. - */ - public static final String DEFAULT_TEMPLATE_NAME = "default"; - - private static final System.Logger LOGGER = System.getLogger(TemplateHelper.class.getName()); - - private final String versionId; - - private TemplateHelper(InjectionServicesConfig cfg) { - Objects.requireNonNull(cfg.providerName(), "provider name is required"); - this.versionId = cfg.providerVersion().orElseThrow(() -> new IllegalStateException("provider version is required")); - } - - /** - * Creates a template helper utility using the global bootstrap configuration. - * - * @return the template helper initialized with the bootstrap configuration - */ - public static TemplateHelper create() { - InjectionServicesConfig cfg = InjectionServices.injectionServices() - .orElseThrow(() -> new ToolsException("Injection services not found")).config(); - return new TemplateHelper(cfg); - } - - /** - * Produces the generated sticker annotation attribute contents. - * - * @param generatorClassTypeName the generator class type name - * @param triggerClassType class that caused the type to be generated - * @param generatedType generated type - * @return the generated sticker - */ - public String generatedStickerFor(TypeName generatorClassTypeName, TypeName triggerClassType, TypeName generatedType) { - return GeneratedAnnotationHandler.createString(generatorClassTypeName, - triggerClassType, - generatedType, - versionId, - ""); - } - - /** - * Apply substitutions. - * - * @param target the target string to find substitutions for - * @param props the replacements - * @param logErr flag indicating whether logger should be written for errors and warnings - * - * @return the new string, fully resolved with substitutions - */ - public String applySubstitutions(CharSequence target, - Map props, - boolean logErr) { - Set missingArgs = new LinkedHashSet<>(); - try { - return applySubstitutions(target.toString(), props, logErr, true, missingArgs, null, null); - } catch (IOException e) { - throw new ToolsException("unable to apply substitutions", e); - } - } - - /** - * Determine the arguments needed for template evaluation. - * - * @param target the target template - * @return the set of attributes that are required for substitution - */ - public Set requiredArguments(String target) { - return requiredArguments(target, Optional.empty(), Optional.empty()); - } - - /** - * Load a template by its fileName using the {@link #DEFAULT_TEMPLATE_NAME}. - * - * @param name the file name - * - * @return the template file, without substitutions applied - */ - String safeLoadTemplate(String name) { - return safeLoadTemplate(DEFAULT_TEMPLATE_NAME, name); - } - - /** - * Load a template by name. - * - * @param templateName the template profile name (e.g., "default") - * @param name the file name - * - * @return the template file, without substitutions applied - */ - String safeLoadTemplate(String templateName, - String name) { - return Objects.requireNonNull(loadTemplate(templateName, name), "failed to load: " + toFQN(templateName, name)); - } - - /** - * Same as {@link #safeLoadTemplate(String, String)} but will return null if the template name is not found. - * - * @param templateName the template profile/directory - * @param name the template name to use - * @return the template, or null if not found - */ - public String loadTemplate(String templateName, - String name) { - return CommonUtils.loadStringFromResource(toFQN(templateName, name)); - } - - /** - * Determine the arguments needed for template evaluation. - * - * @param target the target template - * @param delimStart provides support for custom delimiters - * @param delimEnd provides support for custom delimiters - * @return the set of attributes that are required for substitution - */ - Set requiredArguments(String target, - Optional delimStart, - Optional delimEnd) { - try { - Handlebars handlebars = new Handlebars(); - delimStart.ifPresent(handlebars::setStartDelimiter); - delimEnd.ifPresent(handlebars::setEndDelimiter); - Template template = handlebars.compileInline(target); - Set result = new TreeSet<>(template.collect(TagType.VAR, TagType.SECTION, TagType.STAR_VAR)); - result.addAll(template.collectReferenceParameters()); - result.remove("."); - result.remove("each"); - result.remove("with"); - result.remove("if"); - return result; - } catch (IOException e) { - throw new ToolsException("unable to determine substitutions", e); - } - } - - private static String toFQN(String templateName, - String name) { - return "templates/inject/" + templateName + "/" + name; - } - - private static String applySubstitutions(String target, - Map props, - boolean logErr, - boolean throwOnMissingArgs, - Set missingArgs, - String delimStart, - String delimEnd) throws IOException { - if (target == null) { - return null; - } - - Handlebars handlebars = new Handlebars(); - Template template = handlebars.compileInline(target); - - if (delimStart != null) { - handlebars.setStartDelimiter(delimStart); - } - if (delimEnd != null) { - handlebars.setEndDelimiter(delimEnd); - } - - target = template.apply(props); - - if (!missingArgs.isEmpty()) { - String err = "Unsatisfied substitution of {{...}}: " + missingArgs; - if (logErr) { - LOGGER.log(System.Logger.Level.WARNING, err); - } - if (throwOnMissingArgs) { - throw new IOException(err); - } - } - - return target; - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ToolsException.java b/inject/tools/src/main/java/io/helidon/inject/tools/ToolsException.java deleted file mode 100644 index 04f05a9ddb0..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ToolsException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -/** - * An unchecked exception thrown for any tooling related problem. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public class ToolsException extends RuntimeException { - - /** - * Constructor. - * - * @param msg the message - */ - public ToolsException(String msg) { - super(msg); - } - - /** - * Constructor. - * - * @param msg the message - * @param cause the cause - */ - public ToolsException(String msg, Throwable cause) { - super(msg, cause); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/TypeNames.java b/inject/tools/src/main/java/io/helidon/inject/tools/TypeNames.java deleted file mode 100644 index 5ee9a9fdba6..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/TypeNames.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.runtime.AbstractServiceProvider; - -/** - * Type name constants. - *

- * This should always be used instead of dependency on the annotation and other class types. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public final class TypeNames { - /** - * Package prefix {@value}. - */ - public static final String PREFIX_JAKARTA = "jakarta."; - /** - * Package prefix {@value}. - */ - public static final String PREFIX_JAVAX = "javax."; - - /** - * Injection {@value} type. - */ - public static final String INJECT_APPLICATION = "io.helidon.inject.api.Application"; - - /** - * Injection {@value} annotation. - */ - public static final String CONTRACT = "io.helidon.inject.api.Contract"; - /** - * Injection {@value} annotation. - */ - public static final String EXTERNAL_CONTRACTS = "io.helidon.inject.api.ExternalContracts"; - /** - * Injection {@value} annotation. - */ - public static final String INTERCEPTED = "io.helidon.inject.api.Intercepted"; - /** - * Injection {@value} type. - */ - public static final String INJECT_MODULE = "io.helidon.inject.api.ModuleComponent"; - - /** - * Injection {@value} annotation. - */ - public static final String CONFIGURED_BY = "io.helidon.inject.configdriven.api.ConfiguredBy"; - - /** - * Injection class name {@value} for {@code InjectionPointProvider}. - */ - public static final String INJECTION_POINT_PROVIDER = "io.helidon.inject.api.InjectionPointProvider"; - /** - * Injection {@value INJECTION_POINT_PROVIDER} type. - */ - public static final TypeName INJECTION_POINT_PROVIDER_TYPE = TypeName.create(INJECTION_POINT_PROVIDER); - /** - * Injection service provider type name. - */ - public static final String INJECTION_SERVICE_PROVIDER = "io.helidon.inject.api.ServiceProvider"; - /** - * Injection service provider type. - */ - public static final TypeName SERVICE_PROVIDER_TYPE = TypeName.create("io.helidon.inject.api.ServiceProvider"); - /** - * Injection abstract service provider type. - */ - public static final TypeName ABSTRACT_SERVICE_PROVIDER_TYPE = TypeName.create(AbstractServiceProvider.class); - /** - * Injection class name {@value} for {@code ConfigDrivenServiceProviderBase}. - */ - public static final String ABSTRACT_CONFIGURED_SERVICE_PROVIDER = - "io.helidon.inject.configdriven.runtime.ConfigDrivenServiceProviderBase"; - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_APPLICATION_SCOPED = "jakarta.enterprise.context.ApplicationScoped"; - /** - * Jakarta {@value #JAKARTA_APPLICATION_SCOPED} annotation type. - */ - public static final TypeName JAKARTA_APPLICATION_SCOPED_TYPE = TypeName.create(JAKARTA_APPLICATION_SCOPED); - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_INJECT = "jakarta.inject.Inject"; - /** - * Jakarta {@value #JAKARTA_INJECT} annotation type. - */ - public static final TypeName JAKARTA_INJECT_TYPE = TypeName.create(JAKARTA_INJECT); - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_MANAGED_BEAN = "jakarta.annotation.ManagedBean"; - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_POST_CONSTRUCT = "jakarta.annotation.PostConstruct"; - /** - * Jakarta {@value #JAKARTA_POST_CONSTRUCT} annotation type. - */ - public static final TypeName JAKARTA_POST_CONSTRUCT_TYPE = TypeName.create(JAKARTA_POST_CONSTRUCT); - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_PRE_DESTROY = "jakarta.annotation.PreDestroy"; - /** - * Jakarta {@value #JAKARTA_PRE_DESTROY} annotation type. - */ - public static final TypeName JAKARTA_PRE_DESTROY_TYPE = TypeName.create(JAKARTA_PRE_DESTROY); - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_PRIORITY = "jakarta.annotation.Priority"; - /** - * Jakarta {@value} type. - */ - public static final String JAKARTA_PROVIDER = "jakarta.inject.Provider"; - /** - * Jakarta {@value #JAKARTA_PROVIDER} type. - */ - public static final TypeName JAKARTA_PROVIDER_TYPE = TypeName.create(JAKARTA_PROVIDER); - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_QUALIFIER = "jakarta.inject.Qualifier"; - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_RESOURCE = "jakarta.annotation.Resource"; - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_RESOURCES = "jakarta.annotation.Resources"; - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_SCOPE = "jakarta.inject.Scope"; - /** - * Jakarta {@value #JAKARTA_SCOPE} annotation type. - */ - public static final TypeName JAKARTA_SCOPE_TYPE = TypeName.create(JAKARTA_SCOPE); - /** - * Jakarta {@value} annotation. - */ - public static final String JAKARTA_SINGLETON = "jakarta.inject.Singleton"; - /** - * Jakarta {@value #JAKARTA_SINGLETON} annotation type. - */ - public static final TypeName JAKARTA_SINGLETON_TYPE = TypeName.create(JAKARTA_SINGLETON); - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_ACTIVATE_REQUEST_CONTEXT = "jakarta.enterprise.context.control.ActivateRequestContext"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_ALTERNATIVE = "jakarta.enterprise.inject.Alternative"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_BEFORE_DESTROYED = "jakarta.enterprise.context.BeforeDestroyed"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_CONVERSATION_SCOPED = "jakarta.enterprise.context.ConversationScoped"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_DEPENDENT = "jakarta.enterprise.context.Dependent"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_DESTROYED = "jakarta.enterprise.context.Destroyed"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_DISPOSES = "jakarta.enterprise.inject.Disposes"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_INITIALIZED = "jakarta.enterprise.context.Initialized"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_INTERCEPTED = "jakarta.enterprise.inject.Intercepted"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_MODEL = "jakarta.enterprise.inject.Model"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_NONBINDING = "jakarta.enterprise.util.Nonbinding"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_NORMAL_SCOPE = "jakarta.enterprise.context.NormalScope"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_OBSERVES = "jakarta.enterprise.event.Observes"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_OBSERVES_ASYNC = "jakarta.enterprise.event.ObservesAsync"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_PRODUCES = "jakarta.enterprise.inject.Produces"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_REQUEST_SCOPED = "jakarta.enterprise.context.RequestScoped"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_SESSION_SCOPED = "jakarta.enterprise.context.SessionScoped"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_SPECIALIZES = "jakarta.enterprise.inject.Specializes"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_STEREOTYPE = "jakarta.enterprise.inject.Stereotype"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_TRANSIENT_REFERENCE = "jakarta.enterprise.inject.TransientReference"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_TYPED = "jakarta.enterprise.inject.Typed"; - /** - * Jakarta CDI {@value} annotation. - */ - public static final String JAKARTA_CDI_VETOED = "jakarta.enterprise.inject.Vetoed"; - /** - * Jakarta legacy {@value} annotation. - */ - public static final String JAVAX_APPLICATION_SCOPED = "javax.enterprise.context.ApplicationScoped"; - /** - * Jakarta legacy {@value} annotation. - */ - public static final String JAVAX_INJECT = "javax.inject.Inject"; - /** - * Jakarta legacy {@value #JAVAX_INJECT} annotation type. - */ - public static final TypeName JAVAX_INJECT_TYPE = TypeName.create(JAVAX_INJECT); - /** - * Jakarta legacy {@value} annotation. - */ - public static final String JAVAX_POST_CONSTRUCT = "javax.annotation.PostConstruct"; - /** - * Jakarta legacy {@value} annotation. - */ - public static final String JAVAX_PRE_DESTROY = "javax.annotation.PreDestroy"; - /** - * Jakarta legacy {@value} annotation. - */ - public static final String JAVAX_QUALIFIER = "javax.inject.Qualifier"; - /** - * Jakarta legacy {@value} annotation. - */ - public static final String JAVAX_PRIORITY = "javax.annotation.Priority"; - /** - * Jakarta legacy {@value} type. - */ - public static final String JAVAX_PROVIDER = "javax.inject.Provider"; - /** - * Jakarta legacy {@value JAVAX_PROVIDER} type. - */ - public static final TypeName JAVAX_PROVIDER_TYPE = TypeName.create(JAVAX_PROVIDER); - /** - * Jakarta legacy {@value} annotation. - */ - public static final String JAVAX_SINGLETON = "javax.inject.Singleton"; - - private TypeNames() { - } -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/TypeTools.java b/inject/tools/src/main/java/io/helidon/inject/tools/TypeTools.java deleted file mode 100644 index 18560112039..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/TypeTools.java +++ /dev/null @@ -1,1592 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.File; -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.util.Elements; - -import io.helidon.common.processor.AnnotationFactory; -import io.helidon.common.processor.TypeFactory; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypeValues; -import io.helidon.inject.api.ElementInfo; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.runtime.Dependencies; - -import io.github.classgraph.AnnotationInfo; -import io.github.classgraph.AnnotationInfoList; -import io.github.classgraph.AnnotationParameterValue; -import io.github.classgraph.AnnotationParameterValueList; -import io.github.classgraph.ClassInfo; -import io.github.classgraph.ClassRefTypeSignature; -import io.github.classgraph.ClassTypeSignature; -import io.github.classgraph.FieldInfo; -import io.github.classgraph.MethodInfo; -import io.github.classgraph.MethodInfoList; -import io.github.classgraph.MethodParameterInfo; -import io.github.classgraph.TypeArgument; -import io.github.classgraph.TypeSignature; -import jakarta.inject.Singleton; - -import static io.helidon.common.types.TypeNames.COLLECTION; -import static io.helidon.common.types.TypeNames.LIST; -import static io.helidon.common.types.TypeNames.OPTIONAL; - -/** - * Generically handles generated artifact creation via APT. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public final class TypeTools { - private TypeTools() { - } - - /** - * Converts the provided name to a type name path. - * - * @param typeName the type name to evaluate - * @return the file path expression where dots are translated to file separators - */ - public static String toFilePath(TypeName typeName) { - return toFilePath(typeName, ".java"); - } - - /** - * Converts the provided name to a type name path. - * - * @param typeName the type name to evaluate - * @param fileType the file type, typically ".java" - * @return the file path expression where dots are translated to file separators - */ - public static String toFilePath(TypeName typeName, - String fileType) { - String className = typeName.className(); - String packageName = typeName.packageName(); - if (!CommonUtils.hasValue(packageName)) { - packageName = ""; - } else { - packageName = packageName.replace('.', File.separatorChar); - } - - if (!fileType.startsWith(".")) { - fileType = "." + fileType; - } - - return packageName + File.separatorChar + className + fileType; - } - - /** - * Creates a type name from a classInfo. - * - * @param classInfo the classInfo - * @return the typeName for the class info - */ - static TypeName createTypeNameFromClassInfo(ClassInfo classInfo) { - if (classInfo == null) { - return null; - } - return TypeName.create(classInfo.getName()); - } - - /** - * Creates an instance for an annotation with a value. - * - * @param annotation the annotation - * @return the new instance - * @deprecated switch to using pure annotation processing wherever possible - */ - @Deprecated - static Annotation createAnnotationFromAnnotation(java.lang.annotation.Annotation annotation) { - return Annotation.create(TypeName.create(annotation.annotationType()), extractValues(annotation)); - } - - /** - * Creates an instance from reflective access. Note that this approach will only have visibility to the - * {@link java.lang.annotation.RetentionPolicy#RUNTIME} type annotations. - * - * @param annotations the annotations on the type, method, or parameters - * @return the new instance - * @deprecated switch to use pure annotation processing instead of reflection - */ - @SuppressWarnings("DeprecatedIsStillUsed") - @Deprecated - public static List createAnnotationListFromAnnotations(java.lang.annotation.Annotation[] annotations) { - if (annotations == null || annotations.length <= 0) { - return List.of(); - } - - return Arrays.stream(annotations).map(TypeTools::createAnnotationFromAnnotation).collect(Collectors.toList()); - } - - /** - * Extracts values from the annotation. - * - * @param annotation the annotation - * @return the extracted value - * @deprecated switch to use pure annotation processing instead of reflection - */ - @Deprecated - static Map extractValues(java.lang.annotation.Annotation annotation) { - Map result = new HashMap<>(); - - Class aClass = annotation.annotationType(); - Method[] declaredMethods = aClass.getDeclaredMethods(); - for (Method declaredMethod : declaredMethods) { - String propertyName = declaredMethod.getName(); - try { - Object value = declaredMethod.invoke(annotation); - if (!(value instanceof Annotation)) { - String stringValue; - // check if array - if (value.getClass().isArray()) { - if (value.getClass().getComponentType().equals(Annotation.class)) { - stringValue = "array of annotations"; - } else { - String[] stringArray; - if (value.getClass().getComponentType().equals(String.class)) { - stringArray = (String[]) value; - } else { - stringArray = new String[Array.getLength(value)]; - for (int i = 0; i < stringArray.length; i++) { - stringArray[i] = String.valueOf(Array.get(value, i)); - } - } - - stringValue = String.join(", ", stringArray); - } - } else { - // just convert to String - stringValue = String.valueOf(value); - } - result.put(propertyName, stringValue); - } - } catch (Throwable ignored) { - } - } - return result; - } - - /** - * Extracts values from the annotation info list. - * - * @param values the annotation values - * @return the extracted values - */ - static Map extractValues(AnnotationParameterValueList values) { - return values.asMap().entrySet().stream() - .map(e -> new AbstractMap - .SimpleEntry<>(e.getKey(), toString(e.getValue()))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - /** - * Converts "Optional" or "Provider" -> "Whatever". - * - * @param typeName the type name, that might use generics - * @return the generics component type name - */ - static TypeName componentTypeNameOf(String typeName) { - int pos = typeName.indexOf('<'); - if (pos < 0) { - return TypeName.create(typeName); - } - - int lastPos = typeName.indexOf('>', pos); - assert (lastPos > pos) : typeName; - return TypeName.create(typeName.substring(pos + 1, lastPos)); - } - - /** - * Converts "Optional" or "Provider" -> "Whatever". - * - * @param typeName the type name, that might use generics - * @return the generics component type name - */ - static TypeName componentTypeNameOf(TypeName typeName) { - if (typeName.typeArguments().size() == 1) { - return typeName.typeArguments().get(0); - } - return typeName; - } - - /** - * Creates a set of qualifiers based upon class info introspection. - * - * @param classInfo the class info - * @return the qualifiers - */ - static Set createQualifierSet(ClassInfo classInfo) { - return createQualifierSet(classInfo.getAnnotationInfo()); - } - - /** - * Creates a set of qualifiers based upon method info introspection. - * - * @param methodInfo the method info - * @return the qualifiers - */ - static Set createQualifierSet(MethodInfo methodInfo) { - return createQualifierSet(methodInfo.getAnnotationInfo()); - } - - /** - * Creates a set of qualifiers based upon field info introspection. - * - * @param fieldInfo the field info - * @return the qualifiers - */ - static Set createQualifierSet(FieldInfo fieldInfo) { - return createQualifierSet(fieldInfo.getAnnotationInfo()); - } - - /** - * Creates a set of qualifiers given the owning element. - * - * @param annotationInfoList the list of annotations - * @return the qualifiers - */ - static Set createQualifierSet(AnnotationInfoList annotationInfoList) { - Set set = createAnnotationSetFromMetaAnnotation(annotationInfoList, - TypeNames.JAKARTA_QUALIFIER); - if (set.isEmpty()) { - return Set.of(); - } - - return set.stream() - .map(Qualifier::create) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - /** - * Creates a set of qualifiers given the owning element. - * @param type the element type (from anno processing) - * @return the set of qualifiers that the owning element has - */ - public static Set createQualifierSet(Element type) { - return createQualifierSet(type.getAnnotationMirrors()); - } - - /** - * Creates a set of qualifiers given the owning element's annotation type mirror. - * @param annoMirrors the annotation type mirrors (from anno processing) - * @return the set of qualifiers that the owning element has - */ - public static Set createQualifierSet(List annoMirrors) { - Set result = new LinkedHashSet<>(); - - for (AnnotationMirror annoMirror : annoMirrors) { - if (findAnnotationMirror(TypeNames.JAKARTA_QUALIFIER, annoMirror.getAnnotationType() - .asElement() - .getAnnotationMirrors()) - .isPresent()) { - - String val = null; - for (Map.Entry e : annoMirror.getElementValues() - .entrySet()) { - if (e.getKey().toString().equals("value()")) { - val = String.valueOf(e.getValue().getValue()); - break; - } - } - Qualifier.Builder qualifier = Qualifier.builder(); - qualifier.typeName(TypeFactory.createTypeName(annoMirror.getAnnotationType()).orElseThrow()); - if (val != null) { - qualifier.value(val); - } - result.add(qualifier.build()); - } - } - - if (result.isEmpty()) { - for (AnnotationMirror annoMirror : annoMirrors) { - Optional mirror = findAnnotationMirror(TypeNames.JAVAX_QUALIFIER, - annoMirror.getAnnotationType().asElement() - .getAnnotationMirrors()); - - if (mirror.isPresent()) { - // there is an annotation meta-annotated with @javax.inject.Qualifier, let's add it to the list - Map annoValues = annoMirror.getElementValues(); - - Map values = new HashMap<>(); - annoValues.forEach((method, value) -> { - values.put(method.getSimpleName().toString(), String.valueOf(value.getValue())); - }); - - TypeName annot = TypeName.create(annoMirror.getAnnotationType().toString()); - result.add(Qualifier.builder() - .typeName(annot) - .values(values) - .build()); - } - } - } - - return result; - } - - /** - * Returns the annotations on the type having the meta annotation provided. - * - * @param processingEnv annotation processing environment - * @param type the type to inspect - * @param metaAnnoType the meta annotation type name - * @return the annotations on the type having the meta annotation - */ - public static List annotationsWithAnnotationOf(ProcessingEnvironment processingEnv, - TypeElement type, - String metaAnnoType) { - Set annotations = AnnotationFactory.createAnnotations(type, processingEnv.getElementUtils()); - if (annotations.isEmpty()) { - return List.of(); - } - - List list = annotationsWithAnnotationsOfNoOpposite(type, metaAnnoType); - if (list.isEmpty()) { - list.addAll(annotationsWithAnnotationsOfNoOpposite(type, oppositeOf(metaAnnoType))); - } - - return annotations.stream() - .filter(it -> list.contains(it.typeName().name())) - .collect(Collectors.toList()); - } - - /** - * Creates a set of annotations based upon class info introspection. - * - * @param classInfo the class info - * @return the annotation value set - */ - static Set createAnnotationSet(ClassInfo classInfo) { - return classInfo.getAnnotationInfo() - .stream() - .map(TypeTools::createAnnotation) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - /** - * Creates a set of annotations given the owning element. - * - * @param annotationInfoList the list of annotations - * @return the annotation and value set - */ - public static Set createAnnotationSet(AnnotationInfoList annotationInfoList) { - return annotationInfoList.stream() - .map(TypeTools::createAnnotation) - .collect(Collectors.toCollection(LinkedHashSet::new)); - } - - /** - * Creates an annotation and value from introspection. - * - * @param annotationInfo the introspected annotation - * @return the annotation and value - */ - static Annotation createAnnotation(AnnotationInfo annotationInfo) { - TypeName annoTypeName = createTypeNameFromClassInfo(annotationInfo.getClassInfo()); - return Annotation.create(annoTypeName, extractValues(annotationInfo.getParameterValues())); - } - - /** - * All annotations on every public method and the given type, including all of its methods. - * - * @param classInfo the classInfo of the enclosing class type - * @return the complete set of annotations - */ - static Set gatherAllAnnotationsUsedOnPublicNonStaticMethods(ClassInfo classInfo) { - Set result = new LinkedHashSet<>(createAnnotationSet(classInfo)); - classInfo.getMethodAndConstructorInfo() - .filter(m -> !m.isPrivate() && !m.isStatic()) - .forEach(mi -> result.addAll(createAnnotationSet(mi.getAnnotationInfo()))); - return result; - } - - /** - * All annotations on every public method and the given type, including all of its methods. - * - * @param serviceTypeElement the service type element of the enclosing class type - * @param processEnv the processing environment - * @return the complete set of annotations - */ - static Set gatherAllAnnotationsUsedOnPublicNonStaticMethods(TypeElement serviceTypeElement, - ProcessingEnvironment processEnv) { - Elements elementUtils = processEnv.getElementUtils(); - Set result = new LinkedHashSet<>(); - AnnotationFactory.createAnnotations(serviceTypeElement, processEnv.getElementUtils()).forEach(anno -> { - result.add(anno); - TypeElement typeElement = elementUtils.getTypeElement(anno.typeName().name()); - if (typeElement != null) { - typeElement.getAnnotationMirrors() - .forEach(am -> result.add(AnnotationFactory.createAnnotation(am, processEnv.getElementUtils()))); - } - }); - serviceTypeElement.getEnclosedElements().stream() - .filter(e -> e.getKind() == ElementKind.METHOD) - .filter(e -> !e.getModifiers().contains(javax.lang.model.element.Modifier.PRIVATE)) - .filter(e -> !e.getModifiers().contains(javax.lang.model.element.Modifier.STATIC)) - .map(ExecutableElement.class::cast) - .forEach(exec -> { - exec.getAnnotationMirrors().forEach(am -> { - Annotation anno = AnnotationFactory.createAnnotation(am, processEnv.getElementUtils()); - result.add(anno); - TypeElement typeElement = elementUtils.getTypeElement(anno.typeName().name()); - if (typeElement != null) { - typeElement.getAnnotationMirrors() - .forEach(am2 -> result.add(AnnotationFactory.createAnnotation(am2, - processEnv.getElementUtils()))); - } - }); - }); - return result; - } - - /** - * Creates a set of annotation that are meta-annotated given the owning element. - * - * @param annotationInfoList the list of annotations - * @param metaAnnoType the meta-annotation type - * @return the qualifiers - */ - static Set createAnnotationSetFromMetaAnnotation(AnnotationInfoList annotationInfoList, - String metaAnnoType) { - // resolve meta annotations uses the opposite of already - AnnotationInfoList list = resolveMetaAnnotations(annotationInfoList, metaAnnoType); - if (list == null) { - return Set.of(); - } - - Set result = new LinkedHashSet<>(); - for (AnnotationInfo ai : list) { - TypeName annotationType = translate(TypeName.create(ai.getName())); - AnnotationParameterValueList values = ai.getParameterValues(); - if (values == null || values.isEmpty()) { - result.add(Annotation.create(annotationType)); - } else if (values.size() > 1) { - Map strVals = extractValues(values); - result.add(Annotation.create(annotationType, strVals)); - } else { - Object value = values.get(0).getValue(); - String strValue = (value != null) ? String.valueOf(value) : null; - Annotation annotationAndValue = (strValue == null) - ? Annotation.create(annotationType) - : Annotation.create(annotationType, strValue); - result.add(annotationAndValue); - } - } - return result; - } - - /** - * Extracts all the scope type names from the provided type. - * - * @param processingEnv annotation processing environment - * @param type the type to analyze - * @return the list of all scope type annotation and values - */ - public static List toScopeAnnotations(ProcessingEnvironment processingEnv, TypeElement type) { - List scopeAnnotations = annotationsWithAnnotationOf(processingEnv, type, TypeNames.JAKARTA_SCOPE); - if (scopeAnnotations.isEmpty()) { - scopeAnnotations = annotationsWithAnnotationOf(processingEnv, type, TypeNames.JAKARTA_CDI_NORMAL_SCOPE); - } - - if (Options.isOptionEnabled(Options.TAG_MAP_APPLICATION_TO_SINGLETON_SCOPE)) { - boolean hasApplicationScope = scopeAnnotations.stream() - .map(it -> it.typeName().name()) - .anyMatch(it -> it.equals(TypeNames.JAKARTA_APPLICATION_SCOPED) - || it.equals(TypeNames.JAVAX_APPLICATION_SCOPED)); - if (hasApplicationScope) { - scopeAnnotations.add(Annotation.create(Singleton.class)); - } - } - - return scopeAnnotations; - } - - /** - * Extract the scope name from the given introspected class. - * - * @param classInfo the introspected class - * @return the scope name, or null if no scope found - */ - static TypeName extractScopeTypeName(ClassInfo classInfo) { - AnnotationInfoList list = resolveMetaAnnotations(classInfo.getAnnotationInfo(), TypeNames.JAKARTA_SCOPE); - if (list == null) { - return null; - } - - return translate(TypeName.create(CommonUtils.first(list, false).getName())); - } - - /** - * Returns the methods that have an annotation. - * - * @param classInfo the class info - * @param annoType the annotation - * @return the methods with the annotation - */ - static MethodInfoList methodsAnnotatedWith(ClassInfo classInfo, - String annoType) { - MethodInfoList result = new MethodInfoList(); - classInfo.getMethodInfo() - .stream() - .filter(methodInfo -> hasAnnotation(methodInfo, annoType)) - .forEach(result::add); - return result; - } - - /** - * Returns true if the method has an annotation. - * - * @param methodInfo the method info - * @param annoTypeName the annotation to check - * @return true if the method has the annotation - */ - static boolean hasAnnotation(MethodInfo methodInfo, - String annoTypeName) { - return methodInfo.hasAnnotation(annoTypeName) || methodInfo.hasAnnotation(oppositeOf(annoTypeName)); - } - - /** - * Returns true if the method has an annotation. - * - * @param fieldInfo the field info - * @param annoTypeName the annotation to check - * @return true if the method has the annotation - */ - static boolean hasAnnotation(FieldInfo fieldInfo, - String annoTypeName) { - return fieldInfo.hasAnnotation(annoTypeName) || fieldInfo.hasAnnotation(oppositeOf(annoTypeName)); - } - - /** - * Resolves meta annotations. - * - * @param annoList the complete set of annotations - * @param metaAnnoType the meta-annotation to filter on - * @return the filtered set having the meta-annotation - */ - static AnnotationInfoList resolveMetaAnnotations(AnnotationInfoList annoList, - String metaAnnoType) { - if (annoList == null) { - return null; - } - - AnnotationInfoList result = null; - String metaName2 = oppositeOf(metaAnnoType); - for (AnnotationInfo ai : annoList) { - ClassInfo aiClassInfo = ai.getClassInfo(); - if (aiClassInfo.hasAnnotation(metaAnnoType) || aiClassInfo.hasAnnotation(metaName2)) { - if (result == null) { - result = new AnnotationInfoList(); - } - result.add(ai); - } - } - return result; - } - - /** - * Determines the {@link jakarta.inject.Provider} or {@link InjectionPointProvider} contract type. - * - * @param classInfo class info - * @return the provided type - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - static String providesContractType(ClassInfo classInfo) { - Set candidates = new LinkedHashSet<>(); - - ClassInfo nxt = classInfo; - ToolsException firstTe = null; - while (nxt != null) { - ClassTypeSignature sig = nxt.getTypeSignature(); - List superInterfaces = (sig != null) ? sig.getSuperinterfaceSignatures() : null; - if (superInterfaces != null) { - for (ClassRefTypeSignature superInterface : superInterfaces) { - if (!isProviderType(superInterface)) { - continue; - } - - try { - candidates.add(Objects.requireNonNull( - providerTypeOf(superInterface.getTypeArguments().get(0), classInfo))); - } catch (ToolsException te) { - if (firstTe == null) { - firstTe = te; - } - } - } - } - - nxt = nxt.getSuperclass(); - } - - if (candidates.size() > 1) { - throw new IllegalStateException("Unsupported case where provider provides more than one type: " + classInfo); - } - - if (!candidates.isEmpty()) { - return CommonUtils.first(candidates, false); - } - - if (firstTe != null) { - throw firstTe; - } - - return null; - } - - /** - * Determines the {@link jakarta.inject.Provider} contract type. - * - * @param sig class type signature - * @return the provided type - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - static TypeName providesContractType(TypeSignature sig) { - if (sig instanceof ClassRefTypeSignature csig) { - if (isProviderType(TypeName.create(csig.getFullyQualifiedClassName()))) { - TypeArgument typeArg = csig.getTypeArguments().get(0); - if (!(typeArg.getTypeSignature() instanceof ClassRefTypeSignature)) { - throw new IllegalStateException("Unsupported signature: " + sig); - } - return TypeName.create(typeArg.toString()); - } - } - return null; - } - - /** - * Returns the injection point info given a method element. - * - * @param elemInfo the method element info - * @return the injection point info - */ - static InjectionPointInfo createInjectionPointInfo(MethodInfo elemInfo) { - return createInjectionPointInfo(createTypeNameFromClassInfo(elemInfo.getClassInfo()), elemInfo, null); - } - - /** - * Returns the injection point info given a method element. - * - * @param serviceTypeName the enclosing service type name - * @param elemInfo the method element info - * @param elemOffset optionally, the argument position (or null for the method level) - starts at 1 not 0 - * @return the injection point info - */ - static InjectionPointInfo createInjectionPointInfo(TypeName serviceTypeName, - MethodInfo elemInfo, - Integer elemOffset) { - TypeName elemType; - Set qualifiers; - Set annotations; - AtomicReference isProviderWrapped = new AtomicReference<>(); - AtomicReference isListWrapped = new AtomicReference<>(); - AtomicReference isOptionalWrapped = new AtomicReference<>(); - String ipName; - TypeName ipType; - if (elemOffset != null) { - MethodParameterInfo paramInfo = elemInfo.getParameterInfo()[elemOffset - 1]; - elemType = extractInjectionPointTypeInfo(paramInfo, isProviderWrapped, isListWrapped, isOptionalWrapped); - TypeSignature typeSignature = paramInfo.getTypeSignature(); - typeSignature = typeSignature == null ? paramInfo.getTypeDescriptor() : typeSignature; - ipType = TypeName.create(typeSignature.toString()); - qualifiers = createQualifierSet(paramInfo.getAnnotationInfo()); - annotations = createAnnotationSet(paramInfo.getAnnotationInfo()); - ipName = paramInfo.getName(); - if (ipName == null) { - ipName = "arg" + elemOffset; - } - } else { - elemType = TypeName.create(elemInfo.getTypeDescriptor().getResultType().toString()); - ipType = elemType; - qualifiers = createQualifierSet(elemInfo); - annotations = createAnnotationSet(elemInfo.getAnnotationInfo()); - ipName = elemInfo.getName(); - if (ipName == null) { - ipName = "arg"; - } - } - - String elemName = elemInfo.isConstructor() - ? InjectionPointInfo.CONSTRUCTOR : elemInfo.getName(); - int elemArgs = elemInfo.getParameterInfo().length; - AccessModifier access = toAccess(elemInfo.getModifiers()); - String packageName = serviceTypeName.packageName(); - ServiceInfoCriteria serviceInfo = ServiceInfoCriteria.builder() - .serviceTypeName(elemType) - .build(); - return InjectionPointInfo.builder() - .baseIdentity(Dependencies.toMethodBaseIdentity(elemName, elemArgs, access, packageName)) - .id(Dependencies.toMethodIdentity(elemName, elemArgs, elemOffset, access, packageName)) - .dependencyToServiceInfo(serviceInfo) - .serviceTypeName(serviceTypeName) - .elementName(elemName) - .elementKind(elemInfo.isConstructor() - ? io.helidon.inject.api.ElementKind.CONSTRUCTOR : io.helidon.inject.api.ElementKind.METHOD) - .elementTypeName(elemType) - .elementArgs(elemArgs) - .elementOffset(elemOffset) - .access(access) - .staticDeclaration(isStatic(elemInfo.getModifiers())) - .qualifiers(qualifiers) - .annotations(annotations) - .optionalWrapped(isOptionalWrapped.get()) - .providerWrapped(isProviderWrapped.get()) - .listWrapped(isListWrapped.get()) - .ipName(ipName) - .ipType(ipType) - .build(); - } - - /** - * Returns the method info given a method from introspection. - * - * @param methodInfo the method element info - * @param serviceLevelAnnos the annotation at the class level that should be inherited at the method level - * @return the method info - */ - static MethodElementInfo createMethodElementInfo(MethodInfo methodInfo, - Set serviceLevelAnnos) { - TypeName serviceTypeName = createTypeNameFromClassInfo(methodInfo.getClassInfo()); - TypeName elemType = TypeName.create(methodInfo.getTypeDescriptor().getResultType().toString()); - Set qualifiers = createQualifierSet(methodInfo); - Set annotations = createAnnotationSet(methodInfo.getAnnotationInfo()); - if (serviceLevelAnnos != null) { - annotations.addAll(serviceLevelAnnos); - } - List throwables = extractThrowableTypeNames(methodInfo); - List parameters = createParameterInfo(serviceTypeName, methodInfo); - return MethodElementInfo.builder() - .serviceTypeName(serviceTypeName) - .elementName(methodInfo.isConstructor() - ? InjectionPointInfo.CONSTRUCTOR : methodInfo.getName()) - .elementKind(methodInfo.isConstructor() - ? io.helidon.inject.api.ElementKind.CONSTRUCTOR : io.helidon.inject.api.ElementKind.METHOD) - .elementTypeName(elemType) - .elementArgs(methodInfo.getParameterInfo().length) - .access(toAccess(methodInfo.getModifiers())) - .staticDeclaration(isStatic(methodInfo.getModifiers())) - .annotations(annotations) - .qualifiers(qualifiers) - .throwableTypeNames(throwables) - .parameterInfo(parameters) - .build(); - } - - /** - * Returns the method info given a method from annotation processing. - * - * @param serviceTypeElement the enclosing service type for the provided element - * @param ee the method element info - * @param serviceLevelAnnos the annotation at the class level that should be inherited at the method level - * @return the method info - */ - static MethodElementInfo createMethodElementInfo(ProcessingEnvironment processingEnv, - TypeElement serviceTypeElement, - ExecutableElement ee, - Set serviceLevelAnnos) { - TypeName serviceTypeName = TypeFactory.createTypeName(serviceTypeElement).orElseThrow(); - TypeName elemType = TypeName.create(ee.getReturnType().toString()); - Set qualifiers = createQualifierSet(ee); - Set annotations = AnnotationFactory.createAnnotations(ee, processingEnv.getElementUtils()); - if (serviceLevelAnnos != null) { - annotations.addAll(serviceLevelAnnos); - } - List throwables = extractThrowableTypeNames(ee); - List parameters = createParameterInfo(processingEnv, serviceTypeName, ee); - return MethodElementInfo.builder() - .serviceTypeName(serviceTypeName) - .elementName((ee.getKind() == ElementKind.CONSTRUCTOR) - ? InjectionPointInfo.CONSTRUCTOR : ee.getSimpleName().toString()) - .elementKind((ee.getKind() == ElementKind.CONSTRUCTOR) - ? io.helidon.inject.api.ElementKind.CONSTRUCTOR : io.helidon.inject.api.ElementKind.METHOD) - .elementTypeName(elemType) - .elementArgs(ee.getParameters().size()) - .access(toAccess(ee)) - .staticDeclaration(isStatic(ee)) - .qualifiers(qualifiers) - .annotations(annotations) - .throwableTypeNames(throwables) - .parameterInfo(parameters) - .build(); - } - - /** - * Returns the element info given a method element parameter. - * - * @param serviceTypeName the enclosing service type name - * @param elemInfo the method element info - * @param elemOffset the argument position - starts at 1 not 0 - * @return the element info - */ - static ElementInfo createParameterInfo(TypeName serviceTypeName, - MethodInfo elemInfo, - int elemOffset) { - MethodParameterInfo paramInfo = elemInfo.getParameterInfo()[elemOffset - 1]; - TypeName elemType = TypeName.create(paramInfo.getTypeDescriptor().toString()); - Set annotations = createAnnotationSet(paramInfo.getAnnotationInfo()); - return ElementInfo.builder() - .serviceTypeName(serviceTypeName) - .elementName("p" + elemOffset) - .elementKind(elemInfo.isConstructor() - ? io.helidon.inject.api.ElementKind.CONSTRUCTOR : io.helidon.inject.api.ElementKind.METHOD) - .elementTypeName(elemType) - .elementArgs(elemInfo.getParameterInfo().length) - .elementOffset(elemOffset) - .access(toAccess(elemInfo.getModifiers())) - .staticDeclaration(isStatic(elemInfo.getModifiers())) - .annotations(annotations) - .build(); - } - - /** - * Returns the element info given a method element parameter. - * - * @param processingEnv the processing environment - * @param serviceTypeName the enclosing service type name - * @param elemInfo the method element info - * @param elemOffset the argument position - starts at 1 not 0 - * @return the element info - */ - static ElementInfo createParameterInfo(ProcessingEnvironment processingEnv, - TypeName serviceTypeName, - ExecutableElement elemInfo, - int elemOffset) { - VariableElement paramInfo = elemInfo.getParameters().get(elemOffset - 1); - TypeName elemTypeName = TypeFactory.createTypeName(paramInfo).orElseThrow(); - Set annotations = AnnotationFactory.createAnnotations(paramInfo.getAnnotationMirrors(), - processingEnv.getElementUtils()); - return ElementInfo.builder() - .serviceTypeName(serviceTypeName) - .elementName("p" + elemOffset) - .elementKind(elemInfo.getKind() == ElementKind.CONSTRUCTOR - ? io.helidon.inject.api.ElementKind.CONSTRUCTOR : io.helidon.inject.api.ElementKind.METHOD) - .elementTypeName(elemTypeName) - .elementArgs(elemInfo.getParameters().size()) - .elementOffset(elemOffset) - .access(toAccess(elemInfo)) - .staticDeclaration(isStatic(elemInfo)) - .annotations(annotations) - .build(); - } - - /** - * Returns the injection point info given a field element. - * - * @param serviceTypeName the enclosing service type name - * @param elemInfo the field element info - * @return the injection point info - */ - static InjectionPointInfo createInjectionPointInfo(TypeName serviceTypeName, - FieldInfo elemInfo) { - AtomicReference isProviderWrapped = new AtomicReference<>(); - AtomicReference isListWrapped = new AtomicReference<>(); - AtomicReference isOptionalWrapped = new AtomicReference<>(); - TypeName elemType = extractInjectionPointTypeInfo(elemInfo, isProviderWrapped, isListWrapped, isOptionalWrapped); - Set qualifiers = createQualifierSet(elemInfo); - String elemName = elemInfo.getName(); - String id = Dependencies.toFieldIdentity(elemName, serviceTypeName.packageName()); - ServiceInfoCriteria serviceInfo = ServiceInfoCriteria.builder() - .serviceTypeName(elemType) - .build(); - return InjectionPointInfo.builder() - .baseIdentity(id) - .id(id) - .dependencyToServiceInfo(serviceInfo) - .serviceTypeName(serviceTypeName) - .elementName(elemInfo.getName()) - .elementKind(io.helidon.inject.api.ElementKind.FIELD) - .elementTypeName(elemType) - .access(toAccess(elemInfo.getModifiers())) - .staticDeclaration(isStatic(elemInfo.getModifiers())) - .qualifiers(qualifiers) - .optionalWrapped(isOptionalWrapped.get()) - .providerWrapped(isProviderWrapped.get()) - .listWrapped(isListWrapped.get()) - .ipName(elemInfo.getName()) - .ipType(elemType) - .build(); - } - - /** - * Determines the meta parts making up {@link InjectionPointInfo}. - * - * @param paramInfo the method info - * @param isProviderWrapped set to indicate that the ip is a provided type - * @param isListWrapped set to indicate that the ip is a list type - * @param isOptionalWrapped set to indicate that the ip is am optional type - * @return the return type of the parameter type - */ - static TypeName extractInjectionPointTypeInfo(MethodParameterInfo paramInfo, - AtomicReference isProviderWrapped, - AtomicReference isListWrapped, - AtomicReference isOptionalWrapped) { - TypeSignature sig = Objects.requireNonNull(paramInfo).getTypeSignature(); - if (sig == null) { - sig = Objects.requireNonNull(paramInfo.getTypeDescriptor()); - } - return extractInjectionPointTypeInfo(sig, paramInfo.getMethodInfo(), - isProviderWrapped, isListWrapped, isOptionalWrapped); - } - - /** - * Determines the meta parts making up {@link InjectionPointInfo}. - * - * @param elemInfo the field info - * @param isProviderWrapped set to indicate that the ip is a provided type - * @param isListWrapped set to indicate that the ip is a list type - * @param isOptionalWrapped set to indicate that the ip is an optional type - * @return the return type of the injection point - */ - static TypeName extractInjectionPointTypeInfo(FieldInfo elemInfo, - AtomicReference isProviderWrapped, - AtomicReference isListWrapped, - AtomicReference isOptionalWrapped) { - TypeSignature sig = Objects.requireNonNull(elemInfo).getTypeSignature(); - if (sig == null) { - sig = Objects.requireNonNull(elemInfo.getTypeDescriptor()); - } - return extractInjectionPointTypeInfo(sig, elemInfo.getClassInfo(), - isProviderWrapped, isListWrapped, isOptionalWrapped); - } - - /** - * Determines the meta parts making up {@link InjectionPointInfo} for reflective processing. - * - * @param sig the variable / element type - * @param isProviderWrapped set to indicate that the ip is a provided type - * @param isListWrapped set to indicate that the ip is a list type - * @param isOptionalWrapped set to indicate that the ip is an optional type - * @return the return type of the injection point - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - static TypeName extractInjectionPointTypeInfo(TypeSignature sig, - Object enclosingElem, - AtomicReference isProviderWrapped, - AtomicReference isListWrapped, - AtomicReference isOptionalWrapped) { - ClassRefTypeSignature csig = toClassRefSignature(sig, enclosingElem); - boolean isProvider = false; - boolean isOptional = false; - boolean isList = false; - String varTypeName = csig.toString(); - boolean handled = csig.getTypeArguments().isEmpty(); - if (1 == csig.getTypeArguments().size()) { - isProvider = isProviderType(csig); - isOptional = isOptionalType(csig); - if (isProvider || isOptional) { - ClassRefTypeSignature typeArgSig = toClassRefSignature(csig.getTypeArguments().get(0), enclosingElem); - varTypeName = typeArgSig.toString(); - handled = typeArgSig.getTypeArguments().isEmpty(); - if (!handled) { - TypeName typeArgType = TypeName.create(typeArgSig.getClassInfo().getName()); - if (typeArgType.isOptional() - || typeArgType.isList() - || typeArgType.equals(COLLECTION)) { - // not handled - } else if (isProviderType(typeArgType)) { - isProvider = true; - varTypeName = toClassRefSignature(typeArgSig.getTypeArguments().get(0), enclosingElem).toString(); - handled = true; - } else { - // let's treat it as a supported type ... this is a bit of a gamble though. - handled = true; - } - } - } else if (isListType(csig.getClassInfo().getName())) { - isList = true; - ClassRefTypeSignature typeArgSig = toClassRefSignature(csig.getTypeArguments().get(0), enclosingElem); - varTypeName = typeArgSig.toString(); - handled = typeArgSig.getTypeArguments().isEmpty(); - if (!handled && isProviderType(TypeName.create(typeArgSig.getClassInfo().getName()))) { - isProvider = true; - varTypeName = toClassRefSignature(typeArgSig.getTypeArguments().get(0), enclosingElem).toString(); - handled = true; - } - } - } - - isProviderWrapped.set(isProvider); - isListWrapped.set(isList); - isOptionalWrapped.set(isOptional); - - if (!handled && !isOptional) { - throw new IllegalStateException("Unsupported type for " + csig + " in " + enclosingElem); - } - - return Objects.requireNonNull(componentTypeNameOf(varTypeName)); - } - - /** - * Determines the meta parts making up {@link InjectionPointInfo} for annotation processing. - * - * @param typeElement the variable / element type - * @param isProviderWrapped set to indicate that the ip is a provided type - * @param isListWrapped set to indicate that the ip is a list type - * @param isOptionalWrapped set to indicate that the ip is an optional type - * @return the return type of the injection point - * @throws IllegalStateException thrown if internal state inconsistencies are found - */ - public static TypeName extractInjectionPointTypeInfo(Element typeElement, - AtomicReference isProviderWrapped, - AtomicReference isListWrapped, - AtomicReference isOptionalWrapped) { - TypeMirror typeMirror = typeElement.asType(); - if (!(typeMirror instanceof DeclaredType declaredTypeMirror)) { - throw new IllegalStateException("Unsupported type for " + typeElement.getEnclosingElement() + "." - + typeElement + " with " + typeMirror.getKind()); - } - TypeElement declaredClassType = ((TypeElement) declaredTypeMirror.asElement()); - - boolean isProvider = false; - boolean isOptional = false; - boolean isList = false; - String varTypeName = declaredTypeMirror.toString(); - boolean handled = false; - if (declaredClassType != null) { - handled = declaredTypeMirror.getTypeArguments().isEmpty(); - if (1 == declaredTypeMirror.getTypeArguments().size()) { - isProvider = isProviderType(declaredClassType); - isOptional = isOptionalType(declaredClassType); - if (isProvider || isOptional) { - typeMirror = declaredTypeMirror.getTypeArguments().get(0); - if (typeMirror.getKind() == TypeKind.TYPEVAR) { - typeMirror = ((TypeVariable) typeMirror).getUpperBound(); - } - declaredTypeMirror = (DeclaredType) typeMirror; - declaredClassType = ((TypeElement) declaredTypeMirror.asElement()); - varTypeName = declaredClassType.toString(); - handled = declaredTypeMirror.getTypeArguments().isEmpty(); - if (!handled) { - if (isOptionalType(varTypeName) - || isListType(varTypeName) - || varTypeName.equals(Collections.class.getName())) { - // not handled - } else if (isProviderType(TypeName.create(varTypeName))) { - isProvider = true; - varTypeName = declaredTypeMirror.getTypeArguments().get(0).toString(); - handled = true; - } else { - // let's treat it as a supported type ... this is a bit of a gamble though. - handled = true; - } - } - } else if (isListType(declaredClassType)) { - isList = true; - typeMirror = declaredTypeMirror.getTypeArguments().get(0); - if (typeMirror.getKind() == TypeKind.TYPEVAR) { - typeMirror = ((TypeVariable) typeMirror).getUpperBound(); - } - declaredTypeMirror = (DeclaredType) typeMirror; - declaredClassType = ((TypeElement) declaredTypeMirror.asElement()); - varTypeName = declaredClassType.toString(); - handled = declaredTypeMirror.getTypeArguments().isEmpty(); - if (!handled) { - if (isProviderType(declaredClassType)) { - isProvider = true; - typeMirror = declaredTypeMirror.getTypeArguments().get(0); - declaredTypeMirror = (DeclaredType) typeMirror; - declaredClassType = ((TypeElement) declaredTypeMirror.asElement()); - varTypeName = declaredClassType.toString(); - if (!declaredTypeMirror.getTypeArguments().isEmpty()) { - throw new IllegalStateException("Unsupported generics usage for " + typeMirror + " in " - + typeElement.getEnclosingElement()); - } - handled = true; - } - } - } - } - } - - isProviderWrapped.set(isProvider); - isListWrapped.set(isList); - isOptionalWrapped.set(isOptional); - - if (!handled && !isOptional) { - throw new IllegalStateException("Unsupported type for " + typeElement.getEnclosingElement() - + "." + typeElement + " with " + typeMirror.getKind()); - } - - return Objects.requireNonNull(componentTypeNameOf(varTypeName)); - } - - /** - * Determines whether the type is a {@link jakarta.inject.Provider} (or javax equiv) type. - * - * @param typeElement the type element to check - * @return true if {@link jakarta.inject.Provider} or {@link InjectionPointProvider} - */ - static boolean isProviderType(TypeElement typeElement) { - return isProviderType(TypeName.create(typeElement.getQualifiedName().toString())); - } - - /** - * Determines whether the type is a {@link jakarta.inject.Provider} (or javax equiv) type. - * - * @param typeName the type name to check - * @return true if {@link jakarta.inject.Provider} or {@link InjectionPointProvider} - */ - public static boolean isProviderType(TypeName typeName) { - TypeName type = translate(componentTypeNameOf(typeName)); - return TypeNames.JAKARTA_PROVIDER_TYPE.equals(type) - || TypeNames.JAVAX_PROVIDER_TYPE.equals(type) - || TypeNames.INJECTION_POINT_PROVIDER_TYPE.equals(type); - } - - /** - * Determines whether the type is an {@link java.util.Optional} type. - * - * @param typeElement the type element to check - * @return true if {@link java.util.Optional} - */ - static boolean isOptionalType(TypeElement typeElement) { - return isOptionalType(typeElement.getQualifiedName().toString()); - } - - /** - * Determines whether the type is an {@link java.util.Optional} type. - * - * @param typeName the type name to check - * @return true if {@link java.util.Optional} - */ - static boolean isOptionalType(String typeName) { - return OPTIONAL.equals(componentTypeNameOf(typeName)); - } - - /** - * Determines whether the type is an {@link java.util.List} type. - * - * @param typeElement the type element to check - * @return true if {@link java.util.List} - */ - static boolean isListType(TypeElement typeElement) { - return isListType(typeElement.getQualifiedName().toString()); - } - - /** - * Determines whether the type is an {@link java.util.List} type. - * - * @param typeName the type name to check - * @return true if {@link java.util.List} - */ - static boolean isListType(String typeName) { - return LIST.equals(componentTypeNameOf(typeName)); - } - - /** - * Transposes {@value TypeNames#PREFIX_JAKARTA} from and/or to {@value TypeNames#PREFIX_JAVAX}. - * - * @param typeName the type name to transpose - * @return the transposed value, or the same if not able to be transposed - */ - public static String oppositeOf(String typeName) { - boolean startsWithJakarta = typeName.startsWith(TypeNames.PREFIX_JAKARTA); - boolean startsWithJavax = !startsWithJakarta && typeName.startsWith(TypeNames.PREFIX_JAVAX); - - assert (startsWithJakarta || startsWithJavax) : typeName; - - if (startsWithJakarta) { - return typeName.replace(TypeNames.PREFIX_JAKARTA, TypeNames.PREFIX_JAVAX); - } else { - return typeName.replace(TypeNames.PREFIX_JAVAX, TypeNames.PREFIX_JAKARTA); - } - } - - /** - * Transpose the type name to "jakarta" (if javax is used). - * - * @param typeName the type name - * @return the normalized, transposed value or the original if it doesn't contain javax - */ - static TypeName translate(TypeName typeName) { - if (typeName.packageName().startsWith(TypeNames.PREFIX_JAKARTA)) { - return typeName; - } - - return TypeName.builder(typeName) - .packageName(typeName.packageName().replace(TypeNames.PREFIX_JAVAX, TypeNames.PREFIX_JAKARTA)) - .build(); - } - - /** - * Returns true if the modifiers indicate this is a package private element. - * - * @param modifiers the modifiers - * @return true if package private - */ - static boolean isPackagePrivate(int modifiers) { - return !Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers) && !Modifier.isPublic(modifiers); - } - - /** - * Returns true if the modifiers indicate this is a private element. - * - * @param modifiers the modifiers - * @return true if private - */ - static boolean isPrivate(int modifiers) { - return Modifier.isPrivate(modifiers); - } - - /** - * Returns true if the modifiers indicate this is a static element. - * - * @param modifiers the modifiers - * @return true if static - */ - static boolean isStatic(int modifiers) { - return Modifier.isStatic(modifiers); - } - - /** - * Returns true if the element is static. - * - * @param element the element - * @return true if static - */ - public static boolean isStatic(Element element) { - Set modifiers = element.getModifiers(); - return (modifiers != null) && modifiers.contains(javax.lang.model.element.Modifier.STATIC); - } - - /** - * Returns true if the modifiers indicate this is an abstract element. - * - * @param modifiers the modifiers - * @return true if abstract - */ - static boolean isAbstract(int modifiers) { - return Modifier.isInterface(modifiers) || Modifier.isAbstract(modifiers); - } - - /** - * Returns true if the element is abstract. - * - * @param element the element - * @return true if abstract - */ - public static boolean isAbstract(Element element) { - Set modifiers = element.getModifiers(); - return (modifiers != null) && modifiers.contains(javax.lang.model.element.Modifier.ABSTRACT); - } - - /** - * Converts the modifiers to an {@link AccessModifier} type. - * - * @param modifiers the modifiers - * @return the access - */ - static AccessModifier toAccess(int modifiers) { - if (Modifier.isPublic(modifiers)) { - return AccessModifier.PUBLIC; - } else if (Modifier.isProtected(modifiers)) { - return AccessModifier.PROTECTED; - } else if (Modifier.isPrivate(modifiers)) { - return AccessModifier.PRIVATE; - } else { - return AccessModifier.PACKAGE_PRIVATE; - } - } - - /** - * Converts the modifiers to an {@link AccessModifier} type. - * - * @param modifiers the modifiers - * @return the access - */ - public static AccessModifier toAccess(Set modifiers) { - if (modifiers.contains(TypeValues.MODIFIER_PROTECTED)) { - return AccessModifier.PROTECTED; - } else if (modifiers.contains(TypeValues.MODIFIER_PRIVATE)) { - return AccessModifier.PRIVATE; - } else if (modifiers.contains(TypeValues.MODIFIER_PUBLIC)) { - return AccessModifier.PUBLIC; - } - return AccessModifier.PACKAGE_PRIVATE; - } - - /** - * Determines the access from an {@link javax.lang.model.element.Element} (from anno processing). - * - * @param element the element - * @return the access - */ - public static AccessModifier toAccess(Element element) { - AccessModifier access = AccessModifier.PACKAGE_PRIVATE; - Set modifiers = element.getModifiers(); - if (modifiers != null) { - for (javax.lang.model.element.Modifier modifier : modifiers) { - if (javax.lang.model.element.Modifier.PUBLIC == modifier) { - access = AccessModifier.PUBLIC; - break; - } else if (javax.lang.model.element.Modifier.PROTECTED == modifier) { - access = AccessModifier.PROTECTED; - break; - } else if (javax.lang.model.element.Modifier.PRIVATE == modifier) { - access = AccessModifier.PRIVATE; - break; - } - } - } - return access; - } - - /** - * Returns the kind of the method. - * - * @param methodInfo the method info - * @return the kind - */ - static ElementKind toKind(MethodInfo methodInfo) { - return (methodInfo.isConstructor()) - ? ElementKind.CONSTRUCTOR : ElementKind.METHOD; - } - - /** - * Returns the kind of the method. - * - * @param methodInfo the method info - * @return the kind - */ - static ElementKind toKind(ExecutableElement methodInfo) { - return (methodInfo.getKind() == ElementKind.CONSTRUCTOR) - ? ElementKind.CONSTRUCTOR : ElementKind.METHOD; - } - - /** - * Checks whether the package name need to be declared. - * - * @param packageName the package name - * @return true if the package name needs to be declared - */ - public static boolean needToDeclarePackageUsage(String packageName) { - return !( - packageName.startsWith("java.") - || packageName.startsWith("sun.") - || packageName.toLowerCase().endsWith(".impl") - || packageName.equals("io.helidon.inject.api")); - } - - /** - * Checks whether the module name needs to be declared. - * - * @param moduleName the module name - * @return true if the module name needs to be declared - */ - public static boolean needToDeclareModuleUsage(String moduleName) { - return (moduleName != null) && !moduleName.equals(ModuleInfoDescriptorBlueprint.DEFAULT_MODULE_NAME) - && !( - moduleName.startsWith("java.") - || moduleName.startsWith("sun.") - || moduleName.startsWith("jakarta.inject") - || moduleName.startsWith("io.helidon.inject")); - } - - /** - * Translates a {@link javax.lang.model.type.TypeMirror} into a {@link javax.lang.model.element.TypeElement}. - * - * @param typeMirror the type mirror - * @return the type element - */ - public static Optional toTypeElement(TypeMirror typeMirror) { - if (TypeKind.DECLARED == typeMirror.getKind()) { - TypeElement te = (TypeElement) ((DeclaredType) typeMirror).asElement(); - return (te.toString().equals(Object.class.getName())) ? Optional.empty() : Optional.of(te); - } - return Optional.empty(); - } - - private static String toString(AnnotationParameterValue val) { - if (val == null) { - return null; - } - - Object v = val.getValue(); - if (v == null) { - return null; - } - - Class clazz = v.getClass(); - if (!clazz.isArray()) { - return v.toString(); - } - - Object[] arr = (Object[]) v; - return "{" + CommonUtils.toString(Arrays.asList(arr)) + "}"; - } - - private static List annotationsWithAnnotationsOfNoOpposite(TypeElement type, - String annotation) { - List list = new ArrayList<>(); - type.getAnnotationMirrors() - .forEach(am -> findAnnotationMirror(annotation, - am.getAnnotationType().asElement() - .getAnnotationMirrors()) - .ifPresent(it -> list.add(am.getAnnotationType().asElement().toString()))); - return list; - } - - /** - * Should only be called if the encloser of the typeArgument is known to be Provider type. - */ - private static String providerTypeOf(TypeArgument typeArgument, - Object enclosingElem) { - if (!(typeArgument.getTypeSignature() instanceof ClassRefTypeSignature)) { - throw new IllegalStateException("Unsupported provider<> type of " + typeArgument + " in " + enclosingElem); - } - return typeArgument.toString(); - } - - /** - * Returns the throwable types on a method. - * - * @param methodInfo the method info - * @return the list of throwable type names - */ - private static List extractThrowableTypeNames(MethodInfo methodInfo) { - String[] thrownExceptionNames = methodInfo.getThrownExceptionNames(); - if (thrownExceptionNames == null || thrownExceptionNames.length == 0) { - return List.of(); - } - - return Arrays.asList(thrownExceptionNames); - } - - /** - * Returns the throwable types on a method. - * - * @param methodInfo the method info - * @return the list of throwable type names - */ - private static List extractThrowableTypeNames(ExecutableElement methodInfo) { - List thrownExceptionTypes = methodInfo.getThrownTypes(); - if (thrownExceptionTypes == null) { - return List.of(); - } - return thrownExceptionTypes.stream().map(TypeMirror::toString).collect(Collectors.toList()); - } - - /** - * Returns the list of parameter info through introspection. - * - * @param serviceTypeName the enclosing service type name - * @param methodInfo the method info - * @return the list of info elements/parameters - */ - private static List createParameterInfo(TypeName serviceTypeName, - MethodInfo methodInfo) { - List result = new ArrayList<>(); - int count = 0; - for (MethodParameterInfo ignore : methodInfo.getParameterInfo()) { - count++; - result.add(createParameterInfo(serviceTypeName, methodInfo, count)); - } - return result; - } - - /** - * Returns the list of parameter info through annotation processing. - * - * @param processingEnv the processing environment - * @param serviceTypeName the enclosing service type name - * @param methodInfo the method info - * @return the list of info elements/parameters - */ - private static List createParameterInfo(ProcessingEnvironment processingEnv, - TypeName serviceTypeName, - ExecutableElement methodInfo) { - List result = new ArrayList<>(); - int count = 0; - for (VariableElement ignore : methodInfo.getParameters()) { - count++; - result.add(createParameterInfo(processingEnv, serviceTypeName, methodInfo, count)); - } - return result; - } - - private static ClassRefTypeSignature toClassRefSignature(TypeSignature sig, - Object enclosingElem) { - if (!(Objects.requireNonNull(sig) instanceof ClassRefTypeSignature)) { - throw new IllegalStateException("Unsupported type for " + sig + " in " + enclosingElem); - } - return (ClassRefTypeSignature) sig; - } - - private static ClassRefTypeSignature toClassRefSignature( - TypeArgument arg, - Object enclosingElem) { - return toClassRefSignature(arg.getTypeSignature(), enclosingElem); - } - - private static boolean isProviderType(ClassRefTypeSignature sig) { - return isProviderType(TypeName.create(sig.getFullyQualifiedClassName())); - } - - private static boolean isOptionalType(ClassRefTypeSignature sig) { - return isOptionalType(sig.getFullyQualifiedClassName()); - } - - /** - * Locate an annotation mirror by name. - * - * @param annotationType the annotation type to search for - * @param ams the collection to search through - * @return the annotation mirror, or empty if not found - */ - private static Optional findAnnotationMirror(String annotationType, - Collection ams) { - return ams.stream() - .filter(it -> annotationType.equals(it.getAnnotationType().toString())) - .findFirst(); - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/package-info.java b/inject/tools/src/main/java/io/helidon/inject/tools/package-info.java deleted file mode 100644 index c3b92fe03f8..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Injection Tools. - */ -package io.helidon.inject.tools; diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ActivatorCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/spi/ActivatorCreator.java deleted file mode 100644 index ffa0734e3bf..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ActivatorCreator.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.spi; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.Contract; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.tools.ActivatorCreatorProvider; -import io.helidon.inject.tools.ActivatorCreatorRequest; -import io.helidon.inject.tools.ActivatorCreatorResponse; -import io.helidon.inject.tools.CodeGenInterceptorRequest; -import io.helidon.inject.tools.InterceptorCreatorResponse; - -/** - * Implementors of this contract are responsible for code-generating the - * {@link Activator}s and {@link ServiceProvider}s for service types found in your - * DI-enabled - * module. - *

- * The typical scenario will have 1-SingletonServiceType:1-GeneratedInjectionActivatorClassForThatService:1-ServiceProvider - * representation in the {@link Services} registry that can be lazily activated. - *

- * Activators are only generated if your service is marked as a {@code jakarta.inject.Singleton} scoped service. - *

- * All activators for your jar module are then aggregated and registered into a code-generated - * {@link ModuleComponent} class. - * - * @see ActivatorCreatorProvider - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface ActivatorCreator { - - /** - * Used during annotation processing in compile time to automatically generate {@link Activator}'s - * and optionally an aggregating {@link ModuleComponent} for those activators. - * - * @param request the request for what to generate - * @return the response result for the create operation - */ - ActivatorCreatorResponse createModuleActivators(ActivatorCreatorRequest request); - - /** - * Generates just the interceptors. - * - * @param request the request for what to generate - * @return the response result for the create operation - */ - InterceptorCreatorResponse codegenInterceptors(CodeGenInterceptorRequest request); - - /** - * Generates the would-be implementation type name that will be generated if - * {@link #createModuleActivators(ActivatorCreatorRequest)} were to be called on this creator. - * - * @param activatorTypeName the service/activator type name of the developer provided service type. - * - * @return the code generated implementation type name that would be code generated - */ - TypeName toActivatorImplTypeName(TypeName activatorTypeName); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ApplicationCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/spi/ApplicationCreator.java deleted file mode 100644 index 88afc8fd019..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ApplicationCreator.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.spi; - -import io.helidon.inject.api.Application; -import io.helidon.inject.api.Contract; -import io.helidon.inject.tools.ApplicationCreatorRequest; -import io.helidon.inject.tools.ApplicationCreatorResponse; - -/** - * Implementors of this contract are responsible for creating the {@link Application} instance. - * This is used by Injection maven-plugin. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface ApplicationCreator { - - /** - * Used to create the {@link Application} source for the entire - * application / assembly. - * - * @param request the request for what to generate - * @return the result from the create operation - */ - ApplicationCreatorResponse createApplication(ApplicationCreatorRequest request); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/spi/CustomAnnotationTemplateCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/spi/CustomAnnotationTemplateCreator.java deleted file mode 100644 index 6caf1d6bc2d..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/spi/CustomAnnotationTemplateCreator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.spi; - -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.tools.CustomAnnotationTemplateRequest; -import io.helidon.inject.tools.CustomAnnotationTemplateResponse; - -/** - * Instances of this are found via the service loader during compilation time and called by the - * {@code io.helidon.inject.processor.CustomAnnotationProcessor}. It should be noted that this contract may be - * called multiple times since annotation processing naturally happens over multiple iterations. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface CustomAnnotationTemplateCreator { - - /** - * These are the set of annotation types that will trigger a call this producer. - * - * @return the supported annotation types for this producer - */ - Set annoTypes(); - - /** - * The implementor should return empty if the request should not be handled. - * - * @param request the request - * @return the response that will describe what template to produce, or empty to to cause processing to skip - */ - Optional create(CustomAnnotationTemplateRequest request); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ExternalModuleCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/spi/ExternalModuleCreator.java deleted file mode 100644 index 385ce9a6aba..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ExternalModuleCreator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.spi; - -import io.helidon.inject.api.Contract; -import io.helidon.inject.tools.ActivatorCreatorRequest; -import io.helidon.inject.tools.ExternalModuleCreatorRequest; -import io.helidon.inject.tools.ExternalModuleCreatorResponse; - -/** - * Implementors are responsible for creating an {@link ActivatorCreatorRequest} that can be then passed - * to the - * {@link ActivatorCreator} based upon the scanning and reflective introspection of a set of classes - * found in an external - * jar module. - * This involves a two-step process of first preparing to create using - * {@link #prepareToCreateExternalModule(ExternalModuleCreatorRequest)}, followed by taking the response - * and proceeding - * to call - * {@link ActivatorCreator#createModuleActivators(ActivatorCreatorRequest)}. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface ExternalModuleCreator { - - /** - * Prepares the activator and module creation by reflectively scanning and analyzing the context of the request - * to build a model payload that can then be pipelined to the activator creator. - * - * @param request the request - * @return the response - */ - ExternalModuleCreatorResponse prepareToCreateExternalModule(ExternalModuleCreatorRequest request); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/spi/InterceptorCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/spi/InterceptorCreator.java deleted file mode 100644 index e204b8dc623..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/spi/InterceptorCreator.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.spi; - -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import javax.annotation.processing.ProcessingEnvironment; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Contract; -import io.helidon.inject.api.InterceptedTrigger; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.tools.InterceptionPlan; -import io.helidon.inject.tools.InterceptorCreatorProvider; - -/** - * Provides the strategy used to determine which annotations cause interceptor creation. Only services that are injection- - * activated may qualify for interception. - * - * @see InterceptorCreatorProvider - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -@Contract -public interface InterceptorCreator { - - /** - * Determines the strategy being applied. - * - * @return the strategy being applied - */ - default Strategy strategy() { - return Strategy.BLENDED; - } - - /** - * Applicable when {@link InterceptorCreator.Strategy#ALLOW_LISTED} is in use. - * - * @return the set of type names that should trigger creation - */ - default Set allowListedAnnotationTypes() { - return Set.of(); - } - - /** - * Applicable when {@link InterceptorCreator.Strategy#CUSTOM} is in use. - * - * @param annotationType the annotation type name - * @return true if the annotation type should trigger interceptor creation - */ - default boolean isAllowListed(TypeName annotationType) { - Objects.requireNonNull(annotationType); - return allowListedAnnotationTypes().contains(annotationType); - } - - /** - * Returns the reflection based interceptor processor. - * - * @param interceptedService the service being intercepted - * @param delegateCreator the "real" creator - * @return the processor to use for the given arguments - */ - InterceptorProcessor createInterceptorProcessor(ServiceInfoBasics interceptedService, - InterceptorCreator delegateCreator); - - /** - * Returns the annotation based interceptor processor. - * - * @param interceptedService the service being intercepted - * @param delegateCreator the "real" creator - * @param processEnv the processing environment (should be passed if in annotation processor) - * @return the processor to use for the given arguments - */ - InterceptorProcessor createInterceptorProcessor(ServiceInfoBasics interceptedService, - InterceptorCreator delegateCreator, - ProcessingEnvironment processEnv); - - /** - * The strategy applied for resolving annotations that trigger interception. - */ - enum Strategy { - - /** - * Meta-annotation based. Only annotations annotated with {@link InterceptedTrigger} will - * qualify. - */ - EXPLICIT, - - /** - * All annotations marked as {@link java.lang.annotation.RetentionPolicy#RUNTIME} will qualify, which implicitly - * will also cover all usages of {@link #EXPLICIT}. - */ - ALL_RUNTIME, - - /** - * A call to {@link #allowListedAnnotationTypes()} will be used to determine which annotations qualify. The - * implementation may then cache this result internally for optimal processing. - */ - ALLOW_LISTED, - - /** - * A call to {@link #isAllowListed(io.helidon.common.types.TypeName)} will be used on a case-by-case basis to check - * which annotation types qualify. - */ - CUSTOM, - - /** - * No annotations will qualify in triggering interceptor creation. - */ - NONE, - - /** - * Applies a blend of {@link #EXPLICIT} and {@link #CUSTOM} to determine which annotations qualify (i.e., if - * the annotation is not explicitly marked, then a call is still issued to - * {@link #isAllowListed(io.helidon.common.types.TypeName)}. This - * strategy is typically the default strategy type in use. - */ - BLENDED - - } - - /** - * Abstraction for interceptor processing. - */ - interface InterceptorProcessor { - - /** - * The set of annotation types that are trigger interception. - * - * @return the set of annotation types that are trigger interception - */ - Set allAnnotationTypeTriggers(); - - /** - * Creates the interception plan. - * - * @param interceptorAnnotationTriggers the annotation type triggering the interception creation. - * @return the plan, or empty if there is no interception needed - */ - Optional createInterceptorPlan(Set interceptorAnnotationTriggers); - - } - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ModuleComponentNamer.java b/inject/tools/src/main/java/io/helidon/inject/tools/spi/ModuleComponentNamer.java deleted file mode 100644 index 4df72780607..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/spi/ModuleComponentNamer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.spi; - -import java.util.Collection; -import java.util.Optional; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ModuleComponent; - -/** - * Implementors of these are responsible for choosing the best {@link io.helidon.common.types.TypeName} for any - * {@link ModuleComponent} being generated. Note that this provider will only be called if there is some - * ambiguity in choosing a name (e.g., there are no exports or there is no {@code module-info} for the module being processed, - * etc.) - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -public interface ModuleComponentNamer { - - /** - * Implementors should return the suggested {@link ModuleComponent} package name, or {@code empty} - * to abstain from naming. - * - * @param serviceActivatorTypeNames the set of activator type names to be generated - * @return the suggested package name for the component module, or empty to abstain from naming - */ - Optional suggestedPackageName(Collection serviceActivatorTypeNames); - -} diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/spi/package-info.java b/inject/tools/src/main/java/io/helidon/inject/tools/spi/package-info.java deleted file mode 100644 index 6a3ab54a9c9..00000000000 --- a/inject/tools/src/main/java/io/helidon/inject/tools/spi/package-info.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Tools SPI support. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -package io.helidon.inject.tools.spi; diff --git a/inject/tools/src/main/java/module-info.java b/inject/tools/src/main/java/module-info.java deleted file mode 100644 index 22d4a9df9b3..00000000000 --- a/inject/tools/src/main/java/module-info.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The Injection Tools module. - * @deprecated Helidon inject is deprecated and will be replaced in a future version - */ -@Deprecated(forRemoval = true, since = "4.0.8") -module io.helidon.inject.tools { - - exports io.helidon.inject.tools.spi; - exports io.helidon.inject.tools; - requires handlebars; - requires io.github.classgraph; - requires io.helidon.builder.api; - requires io.helidon.common.config; - requires io.helidon.common.processor; - requires io.helidon.common; - requires jakarta.inject; - requires java.compiler; - requires static io.helidon.config.metadata; - requires static jakarta.annotation; - requires transitive io.helidon.common.types; - requires transitive io.helidon.inject.runtime; - - uses io.helidon.inject.tools.spi.InterceptorCreator; - uses io.helidon.inject.tools.spi.ApplicationCreator; - uses io.helidon.inject.tools.spi.CustomAnnotationTemplateCreator; - uses io.helidon.inject.tools.spi.ExternalModuleCreator; - uses io.helidon.inject.tools.spi.ActivatorCreator; - uses io.helidon.inject.tools.spi.ModuleComponentNamer; - - provides io.helidon.inject.tools.spi.ActivatorCreator - with io.helidon.inject.tools.ActivatorCreatorDefault; - provides io.helidon.inject.tools.spi.ApplicationCreator - with io.helidon.inject.tools.ApplicationCreatorDefault; - provides io.helidon.inject.tools.spi.ExternalModuleCreator - with io.helidon.inject.tools.ExternalModuleCreatorDefault; - provides io.helidon.inject.tools.spi.InterceptorCreator - with io.helidon.inject.tools.InterceptorCreatorDefault; - -} diff --git a/inject/tools/src/main/resources/templates/inject/default/interface-based-interceptor.hbs b/inject/tools/src/main/resources/templates/inject/default/interface-based-interceptor.hbs deleted file mode 100644 index a2035d1dad5..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/interface-based-interceptor.hbs +++ /dev/null @@ -1,108 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packageName}}; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.common.types.TypeValues; -import io.helidon.inject.api.ClassNamed; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.runtime.InterceptedMethod; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -import static io.helidon.common.types.TypeName.create; -import static io.helidon.inject.runtime.Invocation.createInvokeAndSupply; -import static io.helidon.inject.runtime.Invocation.mergeAndCollapse; - -/** - * Injection {@link Interceptor} for {@link {{parent}} }. - */ -// using the interfaces approach -@io.helidon.common.Weight({{weight}}) -@io.helidon.inject.api.Intercepted({{parent}}.class) -@Singleton -@SuppressWarnings("ALL") -{{{generatedanno}}} -public class {{className}} /* extends {{parent}} */ implements {{interfaces}} { - private static final List __serviceLevelAnnotations = List.of({{#servicelevelannotations}} - {{{.}}}{{#unless @last}},{{/unless}}{{/servicelevelannotations}}); -{{#interceptedmethoddecls}} - private static final TypedElementInfo __{{id}} = TypedElementInfo.builder() - {{{.}}} - .build();{{/interceptedmethoddecls}} - - private static final TypeName __serviceTypeName = TypeName.create({{parent}}.class); - - private final Provider<{{parent}}> __provider; - private final ServiceProvider<{{parent}}> __sp; - private final {{parent}} __impl;{{#interceptedelements}} - private final List> __{{id}}__interceptors;{{/interceptedelements}}{{#interceptedelements}} - private final InterceptedMethod<{{parent}}, {{elementTypeName}}> __{{id}}__call;{{/interceptedelements}} - - @Inject - @SuppressWarnings("unchecked") - {{this.className}}({{#annotationtriggertypenames}} - @ClassNamed({{{.}}}.class) List> {{id}},{{/annotationtriggertypenames}} - Provider<{{parent}}> provider) { - this.__provider = Objects.requireNonNull(provider); - this.__sp = (provider instanceof ServiceProvider) ? (ServiceProvider<{{parent}}>) __provider : null; - {{#ctorinterceptedelements}}List> __ctor__interceptors = mergeAndCollapse({{interceptedTriggerTypeNames}}{{#unless @last}}, {{/unless}});{{/ctorinterceptedelements}}{{#interceptedelements}} - this.__{{{id}}}__interceptors = mergeAndCollapse({{interceptedTriggerTypeNames}});{{/interceptedelements}} - - Function call = args -> __provider.get(); - {{parent}} result = createInvokeAndSupply( - InvocationContext.builder() - .serviceProvider(__sp) - .serviceTypeName(__serviceTypeName) - .classAnnotations(__serviceLevelAnnotations) - .elementInfo(__ctor) - .interceptors(__ctor__interceptors) - .build(), - call, - new Object[0]); - this.__impl = Objects.requireNonNull(result);{{#interceptedelements}} - - this.__{{id}}__call = new InterceptedMethod<{{parent}}, {{elementTypeName}}>( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __{{id}}__interceptors, __{{id}}{{elementArgInfo}}) { - @Override - public {{elementTypeName}} invoke(Object... args) throws Throwable { - {{#if hasReturn}}return impl().{{id}}({{objArrayArgs}});{{else}}impl().{{id}}({{objArrayArgs}}); - return null;{{/if}} - } - };{{/interceptedelements}} - } -{{#interceptedelements}} - @Override - {{{methodDecl}}} { - Object[] args = new Object[] { {{args}} }; - {{#if hasReturn}}return {{/if}}createInvokeAndSupply(__{{id}}__call.ctx(), __interceptedArgs -> __{{id}}__call.apply(__interceptedArgs), args); - } -{{/interceptedelements}} -} diff --git a/inject/tools/src/main/resources/templates/inject/default/module-info.hbs b/inject/tools/src/main/resources/templates/inject/default/module-info.hbs deleted file mode 100644 index 84c7b481f3b..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/module-info.hbs +++ /dev/null @@ -1,22 +0,0 @@ -{{! -Copyright (c) 2022, 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{{.}}}{{/header}}{{#hasdescription}}/**{{#description}} - * {{{.}}}{{/description}} - */{{/hasdescription}}{{#generatedanno}} -// {{{.}}}{{/generatedanno}} -module {{name}} { {{#items}}{{#precomments}} -{{{.}}}{{/precomments}} - {{{contents}}};{{/items}} -} diff --git a/inject/tools/src/main/resources/templates/inject/default/no-arg-based-interceptor.hbs b/inject/tools/src/main/resources/templates/inject/default/no-arg-based-interceptor.hbs deleted file mode 100644 index b9b82f1d995..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/no-arg-based-interceptor.hbs +++ /dev/null @@ -1,108 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packageName}}; - -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Function; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.common.types.TypeValues; -import io.helidon.inject.api.ClassNamed; -import io.helidon.inject.api.InvocationContext; -import io.helidon.inject.api.Interceptor; -import io.helidon.inject.api.InvocationException; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.runtime.InterceptedMethod; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -import static io.helidon.common.types.TypeName.create; -import static io.helidon.inject.runtime.Invocation.createInvokeAndSupply; -import static io.helidon.inject.runtime.Invocation.mergeAndCollapse; - -/** - * Injection {@link Interceptor} for {@link {{parent}} }. - */ -// using the no-arg constructor approach -@io.helidon.common.Weight({{weight}}) -@io.helidon.inject.api.Intercepted({{parent}}.class) -@Singleton -@SuppressWarnings("ALL") -{{{generatedanno}}} -public class {{className}} extends {{parent}} { - private static final List __serviceLevelAnnotations = List.of({{#servicelevelannotations}} - {{{.}}}{{#unless @last}},{{/unless}}{{/servicelevelannotations}}); -{{#interceptedmethoddecls}} - private static final TypedElementInfo __{{id}} = TypedElementInfo.builder() - {{{.}}} - .build();{{/interceptedmethoddecls}} - - private static final TypeName __serviceTypeName = TypeName.create({{parent}}.class); - - private final Provider<{{parent}}> __provider; - private final ServiceProvider<{{parent}}> __sp; - private final {{parent}} __impl;{{#interceptedelements}} - private final List> __{{id}}__interceptors;{{/interceptedelements}}{{#interceptedelements}} - private final InterceptedMethod<{{parent}}, {{elementTypeName}}> __{{id}}__call;{{/interceptedelements}} - - @Inject - @SuppressWarnings("unchecked") - {{this.className}}({{#annotationtriggertypenames}} - @ClassNamed({{{.}}}.class) List> {{id}},{{/annotationtriggertypenames}} - Provider<{{parent}}> provider) { - this.__provider = Objects.requireNonNull(provider); - this.__sp = (provider instanceof ServiceProvider) ? (ServiceProvider<{{parent}}>) __provider : null; - {{#ctorinterceptedelements}}List> __ctor__interceptors = mergeAndCollapse({{interceptedTriggerTypeNames}}{{#unless @last}}, {{/unless}});{{/ctorinterceptedelements}}{{#interceptedelements}} - this.__{{{id}}}__interceptors = mergeAndCollapse({{interceptedTriggerTypeNames}});{{/interceptedelements}} - - Function call = args -> __provider.get(); - {{parent}} result = createInvokeAndSupply( - InvocationContext.builder() - .serviceProvider(__sp) - .serviceTypeName(__serviceTypeName) - .classAnnotations(__serviceLevelAnnotations) - .elementInfo(__ctor) - .interceptors(__ctor__interceptors) - .build(), - call, - new Object[0]); - this.__impl = Objects.requireNonNull(result);{{#interceptedelements}} - - this.__{{id}}__call = new InterceptedMethod<{{parent}}, {{elementTypeName}}>( - __impl, __sp, __serviceTypeName, __serviceLevelAnnotations, __{{id}}__interceptors, __{{id}}{{elementArgInfo}}) { - @Override - public {{elementTypeName}} invoke(Object... args) throws Throwable { - {{#if hasReturn}}return impl().{{id}}({{objArrayArgs}});{{else}}impl().{{id}}({{objArrayArgs}}); - return null;{{/if}} - } - };{{/interceptedelements}} - } -{{#interceptedelements}} - @Override - {{{methodDecl}}} { - Object[] args = new Object[] { {{args}} }; - {{#if hasReturn}}return {{/if}}createInvokeAndSupply(__{{id}}__call.ctx(), __interceptedArgs -> __{{id}}__call.apply(__interceptedArgs), args); - } -{{/interceptedelements}} -} diff --git a/inject/tools/src/main/resources/templates/inject/default/service-provider-activator.hbs b/inject/tools/src/main/resources/templates/inject/default/service-provider-activator.hbs deleted file mode 100644 index f021bf635c6..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/service-provider-activator.hbs +++ /dev/null @@ -1,164 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packagename}}; - -import io.helidon.common.Weight; -import io.helidon.common.Weighted; -import io.helidon.common.types.AccessModifier; -import io.helidon.common.types.TypeName; - -import io.helidon.inject.api.DependenciesInfo; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.PostConstructMethod; -import io.helidon.inject.api.PreDestroyMethod; -import io.helidon.inject.api.RunLevel; -import io.helidon.inject.api.ServiceInfo; -import io.helidon.inject.runtime.Dependencies; - -import jakarta.inject.Provider; -import jakarta.inject.Singleton; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - - -import static io.helidon.inject.api.InjectionPointInfo.CONSTRUCTOR; - -/**{{#description}} - * {{{.}}}{{/description}}{{#extraclasscomments}} - * {{{.}}}{{/extraclasscomments}} - */ -// @Singleton{{#weight}} -@Weight({{{.}}}){{/weight}} {{#isrunlevelset}}@RunLevel({{runlevel}}){{/isrunlevelset}} -@SuppressWarnings("unchecked") -{{{generatedanno}}} -public class {{flatclassname}}{{activatorsuffix}}{{{activatorgenericdecl}}} - extends {{{parent}}} { - private static final ServiceInfo serviceInfo = - ServiceInfo.builder() - .serviceTypeName({{packagename}}.{{classname}}.class){{#contracts}} - .addContractImplemented({{.}}.class){{/contracts}}{{#externalcontracts}} - .addExternalContractImplemented({{.}}.class){{/externalcontracts}} - .activatorTypeName({{flatclassname}}{{activatorsuffix}}.class){{^isprovider}}{{#scopetypenames}} - .addScopeTypeName({{{.}}}.class){{/scopetypenames}}{{/isprovider}}{{#qualifiers}} - {{{.}}}{{/qualifiers}}{{#isweightset}} - .declaredWeight({{weight}}){{/isweightset}}{{#isrunlevelset}} - .declaredRunLevel({{runlevel}}){{/isrunlevelset}} - .build(); - - /** - * The global singleton instance for this service provider activator. - */ - public static final {{flatclassname}}{{activatorsuffix}} INSTANCE = new {{flatclassname}}{{activatorsuffix}}(); - - /** - * Default activator constructor. - */ - protected {{flatclassname}}{{activatorsuffix}}() { - {{{constructor}}} - } - - /** - * The service type of the managed service. - * - * @return the service type of the managed service - */ - @Override - public Class serviceType() { - return {{packagename}}.{{classname}}.class; - } -{{#extracodegen}}{{{.}}} -{{/extracodegen}}{{^isprovider}}{{#if issupportsjsr330instrictmode}} - @Override - public boolean isProvider() { - return false; - } -{{/if}}{{/isprovider}}{{#isprovider}} - @Override - public boolean isProvider() { - return true; - } -{{/isprovider}} - @Override - public DependenciesInfo dependencies() { - DependenciesInfo deps = Dependencies.builder({{packagename}}.{{classname}}.class){{#dependencies}} - {{{.}}}{{/dependencies}} - .build(); - return Dependencies.combine(super.dependencies(), deps); - } -{{#isconcrete}}{{#if issupportsjsr330instrictmode}}{{#if injectionorder}} - @Override - protected List serviceTypeInjectionOrder() { - List order = new java.util.ArrayList<>();{{#injectionorder}} - order.add(TypeName.create({{{.}}}.class));{{/injectionorder}} - return order; - } -{{/if}}{{/if}} - @Override - protected {{classname}} createServiceProvider(Map deps) { {{#ctorargs}} - {{{.}}}{{/ctorargs}} - return new {{packagename}}.{{classname}}({{#ctorarglist}}{{.}}{{/ctorarglist}}); - }{{/isconcrete}} -{{#if injectedfields}} - @Override - protected void doInjectingFields(Object t, Map deps, Set injections, io.helidon.common.types.TypeName forServiceType) { - super.doInjectingFields(t, deps, injections, forServiceType);{{#if issupportsjsr330instrictmode}} - if (forServiceType != null && !{{packagename}}.{{classname}}.class.getName().equals(forServiceType)) { - return; - } -{{/if}} - {{classname}} target = ({{classname}}) t;{{#if issupportsjsr330instrictmode}}{{#injectedfields}} - if (injections.add("{{{id}}}")) { - target.{{{.}}}; - }{{/injectedfields}}{{else}}{{#injectedfields}} - target.{{{.}}};{{/injectedfields}}{{/if}} - } -{{/if}}{{#if injectedmethods}} - @Override - protected void doInjectingMethods(Object t, Map deps, Set injections, TypeName forServiceType) { {{#if injectedmethodsskippedinparent}} - if (injections.isEmpty()) { {{#injectedmethodsskippedinparent}} - injections.add("{{{id}}}");{{/injectedmethodsskippedinparent}} - }{{/if}} - super.doInjectingMethods(t, deps, injections, forServiceType); -{{#if issupportsjsr330instrictmode}} - if (forServiceType != null && !{{packagename}}.{{classname}}.class.getName().equals(forServiceType)) { - return; - } -{{/if}} - {{classname}} target = ({{classname}}) t; -{{#if issupportsjsr330instrictmode}}{{#injectedmethods}} - if (injections.add("{{{id}}}")) { - target.{{{.}}}; - }{{/injectedmethods}}{{else}}{{#injectedmethods}} - target.{{{.}}};{{/injectedmethods}}{{/if}} - } -{{/if}}{{#postconstruct}} - @Override - public Optional postConstructMethod() { - {{classname}} target = ({{classname}}) serviceRef().orElseThrow(); - return Optional.of(target::{{.}}); - } -{{/postconstruct}}{{#predestroy}} - @Override - public Optional preDestroyMethod() { - {{classname}} target = ({{classname}}) serviceRef().orElseThrow(); - return Optional.of(target::{{.}}); - } -{{/predestroy}} -} diff --git a/inject/tools/src/main/resources/templates/inject/default/service-provider-application-empty-servicetypebinding.hbs b/inject/tools/src/main/resources/templates/inject/default/service-provider-application-empty-servicetypebinding.hbs deleted file mode 100644 index e54b5d55989..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/service-provider-application-empty-servicetypebinding.hbs +++ /dev/null @@ -1,19 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}/** - * In module name "{{modulename}}". - * @see {@link {{servicetypename}} } - note that there are no known contracts or dependencies for this service type. - */ - // binder.bindTo({{activator}}) diff --git a/inject/tools/src/main/resources/templates/inject/default/service-provider-application-servicetypebinding.hbs b/inject/tools/src/main/resources/templates/inject/default/service-provider-application-servicetypebinding.hbs deleted file mode 100644 index 78060f9dd84..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/service-provider-application-servicetypebinding.hbs +++ /dev/null @@ -1,21 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}/** - * In module name "{{modulename}}". - * @see {@link {{servicetypename}} } - */ - binder.bindTo({{activator}}) - {{#injectionplan}}{{{.}}} - {{/injectionplan}}.commit(); diff --git a/inject/tools/src/main/resources/templates/inject/default/service-provider-application-stub.hbs b/inject/tools/src/main/resources/templates/inject/default/service-provider-application-stub.hbs deleted file mode 100644 index 08c561ed836..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/service-provider-application-stub.hbs +++ /dev/null @@ -1,57 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packagename}}; - -import java.util.Optional; - -import io.helidon.inject.api.Application; -import io.helidon.inject.api.ServiceInjectionPlanBinder; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -/** - * THIS IS A TEMPORARY PLACEHOLDER. - * It is expected that this module should have eventually generated the "final" Application using the maven-plugin - * attached to the compile phase. See the documentation for more information. -*/ -{{{generatedanno}}} -@Singleton {{#modulename}}@Named({{classname}}.NAME){{/modulename}} -public final class {{classname}} implements Application { -{{#modulename}} - static final String NAME = "{{{.}}}"; -{{/modulename}}{{^modulename}} - static final String NAME = "unnamed";{{/modulename}} - - @Override - public Optional named() { - return Optional.of(NAME); - } - - @Override - public String toString() { - return NAME + "(temporary):" + getClass().getName(); - } - - @Override - public void configure(ServiceInjectionPlanBinder binder) { - throw new IllegalStateException("The application is in an invalid state.\n" - + "The injection maven-plugin either did not get run, or failed to generate the final replacement to this class: " + this - + "\nPlease check the logs or consult the documentation."); - } - -} diff --git a/inject/tools/src/main/resources/templates/inject/default/service-provider-application.hbs b/inject/tools/src/main/resources/templates/inject/default/service-provider-application.hbs deleted file mode 100644 index 6b5a75ba487..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/service-provider-application.hbs +++ /dev/null @@ -1,66 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packagename}}; - -import java.util.Optional; - -import io.helidon.inject.api.Application; -import io.helidon.inject.api.ServiceInjectionPlanBinder; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; - -/**{{#description}} - * {{{.}}}{{/description}} - */ -{{{generatedanno}}} -@Singleton {{#modulename}}@Named({{classname}}.NAME){{/modulename}} -public final class {{classname}} implements Application { -{{#modulename}} - static final String NAME = "{{{.}}}";{{/modulename}}{{^modulename}} - static final String NAME = "unnamed";{{/modulename}} - static boolean enabled = true; - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public {{classname}}() { - } - - @Override - public Optional named() { - return Optional.of(NAME); - } - - @Override - public String toString() { - return NAME + ":" + getClass().getName(); - } - - @Override - public void configure(ServiceInjectionPlanBinder binder) { - if (!enabled) { - return; - } -{{#servicetypebindings}} - {{{.}}}{{/servicetypebindings}} - } - -} diff --git a/inject/tools/src/main/resources/templates/inject/default/service-provider-module.hbs b/inject/tools/src/main/resources/templates/inject/default/service-provider-module.hbs deleted file mode 100644 index 57b94c55624..00000000000 --- a/inject/tools/src/main/resources/templates/inject/default/service-provider-module.hbs +++ /dev/null @@ -1,60 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packagename}}; - -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.api.ServiceBinder; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; -import java.util.Optional; - -/**{{#description}} - * {{{.}}}{{/description}} - */ -{{{generatedanno}}} -@Singleton {{#modulename}}@Named({{classname}}.NAME){{/modulename}} -public final class {{classname}} implements ModuleComponent { {{#modulename}} - static final String NAME = "{{{.}}}";{{/modulename}}{{^modulename}} - static final String NAME = "unnamed";{{/modulename}} - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public {{classname}}() { - } - - @Override - public Optional named() { - return Optional.of(NAME); - } - - @Override - public String toString() { - return NAME + ":" + getClass().getName(); - } - - @Override - public void configure(ServiceBinder binder) { -{{#activators}} binder.bind({{{.}}}.INSTANCE); -{{/activators}} - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/AbstractBaseCreator.java b/inject/tools/src/test/java/io/helidon/inject/tools/AbstractBaseCreator.java deleted file mode 100644 index 5f3b18d4de7..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/AbstractBaseCreator.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.ServiceLoader; - -import io.helidon.common.HelidonServiceLoader; - -abstract class AbstractBaseCreator { - - T loadAndCreate(Class iface) { - return HelidonServiceLoader - .create(ServiceLoader.load(iface)) - .iterator() - .next(); - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/ActivatorCreatorDefaultTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/ActivatorCreatorDefaultTest.java deleted file mode 100644 index c4e87021084..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/ActivatorCreatorDefaultTest.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.Collections; -import java.util.List; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.tools.spi.ActivatorCreator; -import io.helidon.inject.tools.testsubjects.HelloInjectionWorldImpl; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; - -/** - * Tests for {@link ActivatorCreatorDefault}. - */ -class ActivatorCreatorDefaultTest extends AbstractBaseCreator { - - final ActivatorCreator activatorCreator = loadAndCreate(ActivatorCreator.class); - - @Test - void sanity() { - assertThat(activatorCreator.getClass(), equalTo(ActivatorCreatorDefault.class)); - } - - /** - * Note that most of the "real" functional testing will need to occur downstream from this module and test. - */ - @Test - void codegenHelloActivator() { - ActivatorCreatorDefault activatorCreator = (ActivatorCreatorDefault) this.activatorCreator; - CodeGenPaths codeGenPaths = CodeGenPaths.builder() - .generatedSourcesPath("target/inject/generated-sources") - .outputPath("target/inject/generated-classes") - .build(); - AbstractFilerMessager directFiler = AbstractFilerMessager - .createDirectFiler(codeGenPaths, System.getLogger(getClass().getName())); - CodeGenFiler filer = CodeGenFiler.create(directFiler); - ActivatorCreatorCodeGen codeGen = ActivatorCreatorCodeGen.builder().build(); - ActivatorCreatorRequest req = ActivatorCreatorRequest.builder() - .serviceTypeNames(List.of(TypeName.create(HelloInjectionWorldImpl.class))) - .generatedServiceTypeNames(List.of(TypeName.create(HelloInjectionWorldImpl.class))) - .codeGen(codeGen) - .codeGenPaths(codeGenPaths) - .configOptions(ActivatorCreatorConfigOptions.builder().build()) - .filer(filer) - .build(); - - ToolsException te = assertThrows(ToolsException.class, () -> activatorCreator.createModuleActivators(req)); - assertThat(te.getMessage(), is("Failed in create")); - - ActivatorCreatorRequest req2 = ActivatorCreatorRequest.builder() - .serviceTypeNames(Collections.singletonList(TypeName.create(HelloInjectionWorldImpl.class))) - .generatedServiceTypeNames(Collections.singletonList(TypeName.create(HelloInjectionWorldImpl.class))) - .codeGenPaths(CodeGenPaths.builder().build()) - .throwIfError(Boolean.FALSE) - .codeGen(codeGen) - .configOptions(ActivatorCreatorConfigOptions.builder().build()) - .filer(filer) - .build(); - ActivatorCreatorResponse res = activatorCreator.createModuleActivators(req2); - assertThat(res.toString(), res.success(), is(false)); - assertThat(res.error().orElseThrow().getMessage(), equalTo("Failed in create")); - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/ApplicationCreatorDefaultTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/ApplicationCreatorDefaultTest.java deleted file mode 100644 index 23b4627217d..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/ApplicationCreatorDefaultTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; -import io.helidon.inject.tools.spi.ApplicationCreator; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; - -/** - * Tests for {@link ActivatorCreatorDefault}. - */ -class ApplicationCreatorDefaultTest extends AbstractBaseCreator { - - final ApplicationCreator applicationCreator = loadAndCreate(ApplicationCreator.class); - - @Test - void sanity() { - assertThat(applicationCreator.getClass(), equalTo(ApplicationCreatorDefault.class)); - } - - /** - * Most of the testing will need to occur downstream from this module. - */ - @Test - void codegenHelloWorldApplication() { - ApplicationCreator creator = this.applicationCreator; - ServiceInfoCriteria allServices = ServiceInfoCriteria.builder().build(); - - InjectionServices injectionServices = InjectionServices.injectionServices().orElseThrow(); - Services services = injectionServices.services(); - List> serviceProviders = services.lookupAll(allServices); - assertThat(serviceProviders.size(), is(0)); - - List serviceTypeNames = serviceProviders.stream() - .map(sp -> sp.serviceInfo().serviceTypeName()) - .toList(); - - // note: this test needs to align with target/inject/... for this to work/test properly - CodeGenPaths codeGenPaths = CodeGenPaths.builder() - .generatedSourcesPath("target/inject/generated-sources") - .outputPath("target/inject/generated-classes") - .build(); - AbstractFilerMessager directFiler = AbstractFilerMessager - .createDirectFiler(codeGenPaths, System.getLogger(getClass().getName())); - CodeGenFiler filer = CodeGenFiler.create(directFiler); - - String classpath = System.getProperty("java.class.path"); - String separator = System.getProperty("path.separator"); - String[] ignoredClasspath = classpath.split(separator); - ApplicationCreatorRequest req = ApplicationCreatorRequest.builder() - .codeGen(ApplicationCreatorCodeGen.builder() - .className(ActivatorCreatorDefault.applicationClassName("test")) - .classPrefixName("test") - .build()) - .codeGenPaths(codeGenPaths) - .configOptions(ApplicationCreatorConfigOptions.builder() - .permittedProviderTypes(PermittedProviderType.ALL) - .build()) - .filer(filer) - .messager(directFiler) - .serviceTypeNames(serviceTypeNames) - .generatedServiceTypeNames(serviceTypeNames) - .build(); - - ApplicationCreatorResponse res = creator.createApplication(req); - assertThat(res.error(), optionalEmpty()); - assertThat(res.success(), is(true)); - assertThat(res.serviceTypeNames().stream().map(TypeName::name).collect(Collectors.toList()), - contains("inject.Injection$$TestApplication")); - assertThat(res.templateName(), equalTo("default")); - assertThat(res.moduleName(), optionalEmpty()); - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/ExternalModuleCreatorDefaultTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/ExternalModuleCreatorDefaultTest.java deleted file mode 100644 index 6831a434357..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/ExternalModuleCreatorDefaultTest.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.tools.spi.ActivatorCreator; -import io.helidon.inject.tools.spi.ExternalModuleCreator; - -import org.atinject.tck.auto.Drivers; -import org.atinject.tck.auto.DriversSeat; -import org.atinject.tck.auto.accessories.SpareTire; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.notNullValue; - -/** - * Tests for {@link ExternalModuleCreatorDefault}. This test - * effectively demonstrates the behavior of the injection {@code maven-plugin}. - */ -class ExternalModuleCreatorDefaultTest extends AbstractBaseCreator { - - final ExternalModuleCreator externalModuleCreator = loadAndCreate(ExternalModuleCreator.class); - - @Test - void sanity() { - assertThat(externalModuleCreator.getClass(), equalTo(ExternalModuleCreatorDefault.class)); - } - - @Test - void tck330Gen() { - Thread.currentThread().setContextClassLoader(ExternalModuleCreatorDefaultTest.class.getClassLoader()); - - CodeGenPaths codeGenPaths = CodeGenPaths.builder() - .generatedSourcesPath("target/inject/generated-sources") - .outputPath("target/inject/generated-classes") - .build(); - AbstractFilerMessager directFiler = AbstractFilerMessager - .createDirectFiler(codeGenPaths, System.getLogger(getClass().getName())); - CodeGenFiler filer = CodeGenFiler.create(directFiler); - - ActivatorCreatorConfigOptions activatorCreatorConfigOptions = ActivatorCreatorConfigOptions.builder() - .supportsJsr330InStrictMode(true) - .build(); - - ExternalModuleCreatorRequest req = ExternalModuleCreatorRequest.builder() - .addPackageNamesToScan("org.atinject.tck.auto") - .addPackageNamesToScan("org.atinject.tck.auto.accessories") - .addServiceTypeToQualifiersMap(SpareTire.class.getName(), - Set.of(Qualifier.createNamed("spare"))) - .addServiceTypeToQualifiersMap(DriversSeat.class.getName(), - Set.of(Qualifier.create(Drivers.class))) - .activatorCreatorConfigOptions(activatorCreatorConfigOptions) - .innerClassesProcessed(false) - .codeGenPaths(codeGenPaths) - .filer(filer) - .build(); - ExternalModuleCreatorResponse res = externalModuleCreator.prepareToCreateExternalModule(req); - assertThat(res.toString(), res.success(), is(true)); - List desc = res.serviceTypeNames().stream().map(TypeName::name).collect(Collectors.toList()); - assertThat(desc, containsInAnyOrder( - "org.atinject.tck.auto.Convertible", - "org.atinject.tck.auto.DriversSeat", - "org.atinject.tck.auto.Engine", - "org.atinject.tck.auto.FuelTank", - "org.atinject.tck.auto.GasEngine", - "org.atinject.tck.auto.Seat", - "org.atinject.tck.auto.Seatbelt", - "org.atinject.tck.auto.Tire", - "org.atinject.tck.auto.V8Engine", - "org.atinject.tck.auto.accessories.Cupholder", - "org.atinject.tck.auto.accessories.RoundThing", - "org.atinject.tck.auto.accessories.SpareTire" - )); - assertThat(res.moduleName(), optionalValue(equalTo("jakarta.inject.tck"))); - assertThat(res.activatorCreatorRequest(), notNullValue()); - - ActivatorCreator activatorCreator = loadAndCreate(ActivatorCreator.class); - ActivatorCreatorResponse response = activatorCreator.createModuleActivators(res.activatorCreatorRequest()); - assertThat(response.toString(), response.success(), is(true)); - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/InterceptorCreatorDefaultTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/InterceptorCreatorDefaultTest.java deleted file mode 100644 index aaca2c86faf..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/InterceptorCreatorDefaultTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.util.Set; - -import io.helidon.common.types.Annotation; -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.InterceptedTrigger; -import io.helidon.inject.api.ServiceInfoBasics; -import io.helidon.inject.tools.spi.InterceptorCreator; -import io.helidon.inject.tools.testsubjects.HelloInjectionWorld; -import io.helidon.inject.tools.testsubjects.HelloInjectionWorldImpl; - -import jakarta.inject.Named; -import jakarta.inject.Singleton; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; - -class InterceptorCreatorDefaultTest extends AbstractBaseCreator { - - final InterceptorCreator interceptorCreator = loadAndCreate(InterceptorCreator.class); - - @Test - void sanity() { - assertThat(interceptorCreator.getClass(), equalTo(InterceptorCreatorDefault.class)); - assertThat(interceptorCreator.strategy(), is(InterceptorCreator.Strategy.BLENDED)); - assertThat(interceptorCreator.allowListedAnnotationTypes().size(), is(0)); - assertThat(interceptorCreator.isAllowListed(TypeName.create(Named.class)), is(false)); - } - - @Test - void resolverByReflection() { - InterceptorCreatorDefault.AnnotationTypeNameResolver resolver = InterceptorCreatorDefault.createResolverFromReflection(); - assertThat(resolver.resolve(TypeName.create(InterceptedTrigger.class)), - containsInAnyOrder( - Annotation.create(Documented.class), - Annotation.create(Retention.class, "java.lang.annotation.RetentionPolicy.CLASS"), - Annotation.create(Target.class, "{java.lang.annotation.ElementType.ANNOTATION_TYPE}"), - Annotation.builder() - .type(Deprecated.class) - .putValue("forRemoval", "true") - .putValue("since", "4.0.8") - .build() - )); - } - - @Test - void interceptorPlanByReflection() { - ServiceInfoBasics serviceInfoBasics = ServiceInfoBasics.builder() - .serviceTypeName(HelloInjectionWorldImpl.class) - .build(); - InterceptorCreatorDefault.AbstractInterceptorProcessor processor = - (InterceptorCreatorDefault.AbstractInterceptorProcessor) - interceptorCreator.createInterceptorProcessor(serviceInfoBasics, interceptorCreator); - InterceptionPlan plan = processor.createInterceptorPlan(Set.of(TypeName.create(Singleton.class.getName()))) - .orElseThrow(); - assertThat(plan.hasNoArgConstructor(), - is(false)); - assertThat(plan.interfaces(), - contains(TypeName.create(HelloInjectionWorld.class))); - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/ModuleInfoDescriptorTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/ModuleInfoDescriptorTest.java deleted file mode 100644 index 2e7d1399ae7..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/ModuleInfoDescriptorTest.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.io.File; -import java.util.List; - -import io.helidon.inject.api.Contract; -import io.helidon.inject.api.ExternalContracts; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class ModuleInfoDescriptorTest { - - @Test - void programmatic() { - ModuleInfoDescriptor.Builder builder = ModuleInfoDescriptor.builder(); - String typeName = "io.helidon.inject.tools.ModuleInfoDescriptor"; - assertThat(builder.build().contents(), - equalTo("// @io.helidon.common.Generated(value = \"" - + typeName + "\", trigger = \"" - + typeName + "\")\n" - + "module unnamed {\n" - + "}")); - builder.name("my.module"); - builder.descriptionComment("comments here."); - builder.addItem(ModuleInfoUtil.requiresModuleName("their.module", true, false, List.of())); - assertThat(builder.build().contents(), - equalTo("/**\n" - + " * comments here.\n" - + " */\n" - + "// @io.helidon.common.Generated(value = \"" - + typeName + "\", trigger = \"" - + typeName + "\")\n" - + "module my.module {\n" - + " requires transitive their.module;\n" - + "}")); - - builder.addItem(ModuleInfoUtil.usesExternalContract(ExternalContracts.class)); - assertThat(builder.build().contents(), - equalTo("/**\n" - + " * comments here.\n" - + " */\n" - + "// @io.helidon.common.Generated(value = \"" - + typeName + "\", trigger = \"" - + typeName + "\")\n" - + "module my.module {\n" - + " requires transitive their.module;\n" - + " uses " + ExternalContracts.class.getName() + ";\n" - + "}")); - - builder.addItem(ModuleInfoUtil.providesContract(Contract.class.getName(), "some.impl")); - assertThat(builder.build().contents(), - equalTo("/**\n" - + " * comments here.\n" - + " */\n" - + "// @io.helidon.common.Generated(value = \"" - + typeName + "\", trigger = \"" - + typeName + "\")\n" - + "module my.module {\n" - + " requires transitive their.module;\n" - + " uses " + ExternalContracts.class.getName() + ";\n" - + " provides " + Contract.class.getName() + " with some.impl;\n" - + "}")); - } - - @Test - void firstUnqualifiedExport() { - ModuleInfoDescriptor descriptor = ModuleInfoDescriptor.builder() - .name("test") - .addItem(ModuleInfoUtil.providesContract("cn2", "impl2")) - .addItem(ModuleInfoUtil.providesContract("cn1", "impl1")) - .addItem(ModuleInfoUtil.exportsPackage("export1", "private.module.name")) - .addItem(ModuleInfoUtil.exportsPackage("export2")) - .build(); - - String typeName = "io.helidon.inject.tools.ModuleInfoDescriptor"; - assertThat(descriptor.contents(), - equalTo("// @io.helidon.common.Generated(value = \"" - + typeName + "\", trigger = \"" - + typeName + "\")\n" - + "module test {\n" - + " provides cn2 with impl2;\n" - + " provides cn1 with impl1;\n" - + " exports export1 to private.module.name;\n" - + " exports export2;\n" - + "}")); - - assertThat(descriptor.firstUnqualifiedPackageExport().orElseThrow(), - equalTo("export2")); - ModuleInfoItem moduleInfoItem = ModuleInfoItem.builder().provides(true).target("cn1").build(); - assertThat(descriptor.first(moduleInfoItem).orElseThrow().provides(), - is(true)); - } - - @Test - void sortedWithComments() { - ModuleInfoDescriptor descriptor = ModuleInfoDescriptor.builder() - .ordering(ModuleInfoOrdering.SORTED) - .name("test") - .addItem(ModuleInfoUtil.providesContract("cn2", "impl2")) - .addItem(ModuleInfoUtil.providesContract("cn1", "impl1")) - .addItem(ModuleInfoUtil.exportsPackage("export2")) - .addItem(ModuleInfoItem.builder() - .exports(true) - .target("export1") - .addWithOrTo("private.module.name") - .addWithOrTo("another.private.module.name") - .addPrecomment(" // this is an export1 comment") - .build()) - .build(); - - String typeName = "io.helidon.inject.tools.ModuleInfoDescriptor"; - assertThat(descriptor.contents(), - equalTo("// @io.helidon.common.Generated(value = \"" - + typeName + "\", trigger = \"" - + typeName + "\")\n" - + "module test {\n" - + " provides cn1 with impl1;\n" - + " provides cn2 with impl2;\n" - + " // this is an export1 comment\n" - + " exports export1 to another.private.module.name,\n" - + "\t\t\tprivate.module.name;\n" - + " exports export2;\n" - + "}")); - } - - @Test - void innerCommentsNotSupported() { - String moduleInfo = "module test {\nprovides /* inner comment */ cn;\n}"; - ToolsException te = assertThrows(ToolsException.class, - () -> ModuleInfoDescriptor - .create(moduleInfo, ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS, true)); - assertThat(te.getMessage(), - equalTo("Unable to load or parse module-info: module test {\nprovides /* inner comment */ cn;\n}")); - - ModuleInfoDescriptor descriptor = ModuleInfoDescriptor.create(moduleInfo); - assertThat(descriptor.handled(), - is(false)); - assertThat(descriptor.unhandledLines(), - contains("module test {")); - assertThat(descriptor.error().orElseThrow().getMessage(), - equalTo("Unable to load or parse module-info: module test {\nprovides /* inner comment */ cn;\n}")); - } - - // filed https://github.com/helidon-io/helidon/issues/5697 - @Test - void annotationsNotSupported() { - String moduleInfo = "import io.helidon.common.features.api.Feature;\n" - + "import io.helidon.common.features.api.HelidonFlavor;\n" - + "\n" - + "/**\n" - + " * Helidon SE Config module.\n" - + " *\n" - + " * @see io.helidon.config\n" - + " */\n" - + "@Feature(value = \"Config\",\n" - + " description = \"Configuration module\",\n" - + " in = {HelidonFlavor.SE}\n" - + ")\n" - + "module io.helidon.config {\n}\n"; - ToolsException te = assertThrows(ToolsException.class, - () -> ModuleInfoDescriptor - .create(moduleInfo, ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS, true)); - assertThat(te.getCause().getMessage(), - equalTo("Failed to parse line: @Feature(value = \"Config\", description = \"Configuration module\", " - + "in = {HelidonFlavor.SE}")); - - ModuleInfoDescriptor descriptor = ModuleInfoDescriptor.create(moduleInfo); - assertThat(descriptor.handled(), - is(false)); - assertThat(descriptor.unhandledLines(), - contains("@Feature(value = \"Config\", description = \"Configuration module\", in = {HelidonFlavor.SE}")); - assertThat(descriptor.error().orElseThrow().getCause().getMessage(), - equalTo("Failed to parse line: @Feature(value = \"Config\", description = \"Configuration module\", " - + "in = {HelidonFlavor.SE}")); - } - - @Test - void loadCreateAndSave() throws Exception { - ModuleInfoDescriptor descriptor = ModuleInfoDescriptor - .create(CommonUtils.loadStringFromResource("testsubjects/m0._java_"), - ModuleInfoOrdering.NATURAL, true); - assertThat(descriptor.contents(false), - equalTo("module io.helidon.inject {\n" - + " requires transitive io.helidon.inject.api;\n" - + " requires static com.fasterxml.jackson.annotation;\n" - + " requires static lombok;\n" - + " requires io.helidon.common;\n" - + " exports io.helidon.inject.spi.impl;\n" - + " provides io.helidon.inject.api.InjectionServices with io.helidon.inject.spi.impl" - + ".DefaultInjectionServices;\n" - + " uses io.helidon.inject.api.ModuleComponent;\n" - + " uses io.helidon.inject.api.Application;\n" - + " opens io.helidon.config to weld.core.impl,\n" - + " io.helidon.microprofile.cdi;\n" - + "}")); - - String contents = CommonUtils.loadStringFromFile("target/test-classes/testsubjects/m0._java_").trim(); - descriptor = ModuleInfoDescriptor.create(contents, ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS, true); - assertThat(descriptor.contents(false), - equalTo(contents)); - - File tempFile = null; - try { - tempFile = File.createTempFile("module-info", ""); - descriptor.save(tempFile.toPath()); - - String contents2 = CommonUtils.loadStringFromFile("target/test-classes/testsubjects/m0._java_").trim(); - assertThat(contents, equalTo(contents2)); - ModuleInfoDescriptor descriptor2 = - ModuleInfoDescriptor.create(contents, ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS, true); - assertThat(descriptor, equalTo(descriptor2)); - } finally { - if (tempFile != null) { - tempFile.delete(); - } - } - } - - @Test - void mergeCreate() { - ModuleInfoDescriptor descriptor = ModuleInfoDescriptor - .create(CommonUtils.loadStringFromResource("testsubjects/m0._java_"), - ModuleInfoOrdering.NATURAL_PRESERVE_COMMENTS, true); - assertThat(descriptor.contents(false), - equalTo("module io.helidon.inject {\n" - + "\n" - + " requires transitive io.helidon.inject.api;\n" - + " requires static com.fasterxml.jackson.annotation;\n" - + " requires static lombok;\n" - + " requires io.helidon.common;\n" - + "\n" - + " exports io.helidon.inject.spi.impl;\n" - + "\n" - + " provides io.helidon.inject.api.InjectionServices with io.helidon.inject.spi.impl" - + ".DefaultInjectionServices;\n" - + "\n" - + " uses io.helidon.inject.api.ModuleComponent;\n" - + " uses io.helidon.inject.api.Application;\n" - + "\n" - + " // needed when running with modules - to make private methods accessible\n" - + " // another comment with a semicolon;\n" - + " opens io.helidon.config to weld.core.impl,\n" - + " io.helidon.microprofile.cdi;\n" - + "}")); - IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> descriptor.mergeCreate(descriptor)); - assertThat(e.getMessage(), equalTo("can't merge with self")); - - ModuleInfoDescriptor mergeCreated = descriptor.mergeCreate(ModuleInfoDescriptor.builder(descriptor).build()); - assertThat(descriptor.contents(), equalTo(mergeCreated.contents())); - - ModuleInfoDescriptor descriptor1 = ModuleInfoDescriptor.builder() - .addItem(ModuleInfoUtil.exportsPackage("one")) - .build(); - ModuleInfoDescriptor descriptor2 = ModuleInfoDescriptor.builder() - .addItem(ModuleInfoUtil.exportsPackage("two")) - .build(); - mergeCreated = descriptor1.mergeCreate(descriptor2); - assertThat(mergeCreated.contents(false), - equalTo("module unnamed {\n" - + " exports one;\n" - + " exports two;\n" - + "}")); - } - - @Test - void addIfAbsent() { - ModuleInfoDescriptor.Builder builder = ModuleInfoDescriptor.builder(); - ModuleInfoUtil.addIfAbsent(builder, "external", - () -> ModuleInfoItem.builder() - .uses(true) - .target("external") - .addPrecomment(" // 1") - .build()); - ModuleInfoUtil.addIfAbsent(builder, "external", - () -> ModuleInfoItem.builder() - .uses(true) - .target("external") - .addPrecomment(" // 2") - .build()); - ModuleInfoDescriptor descriptor = builder.build(); - assertThat(descriptor.contents(false), - equalTo("module unnamed {\n" - + " // 1\n" - + " uses external;\n" - + "}")); - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/TemplateHelperTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/TemplateHelperTest.java deleted file mode 100644 index d28dcc9d382..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/TemplateHelperTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import io.helidon.common.types.TypeName; - -import org.junit.jupiter.api.Test; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class TemplateHelperTest { - - @Test - void bogusTemplateName() { - TemplateHelper helper = TemplateHelper.create(); - ToolsException e = assertThrows(ToolsException.class, - () -> helper.safeLoadTemplate("bogus.hbs")); - assertThat(e.getMessage(), equalTo("Failed to load: templates/inject/default/bogus.hbs")); - } - - @Test - void requiredArguments() { - TemplateHelper helper = TemplateHelper.create(); - Set args = helper.requiredArguments("this is {a} little {test}", Optional.of("{"), Optional.of("}")); - assertThat(args, contains("a", "test")); - - args = helper.requiredArguments("this is a little test"); - assertThat(args, empty()); - - args = helper.requiredArguments("this is a {{little}} test"); - assertThat(args, contains("little")); - } - - @Test - public void applyMustacheSubstitutions() { - TemplateHelper helper = TemplateHelper.create(); - Map props = Map.of("little", "big"); - - String val = helper.applySubstitutions("", props, true); - assertThat(val, equalTo("")); - - val = helper.applySubstitutions("this is a {{little}} test", props, true); - assertThat(val, equalTo("this is a big test")); - } - - @Test - public void moduleInfoTemplate() { - Map subst = new HashMap<>(); - TemplateHelper helper = TemplateHelper.create(); - String template = helper.safeLoadTemplate("module-info.hbs"); - - Set args = helper.requiredArguments(template); - assertThat(args, - containsInAnyOrder("description", "hasdescription", "header", "generatedanno", "precomments", "items", "name")); - - String codegen = helper.applySubstitutions(template, subst, true).trim(); - assertThat(codegen, - equalTo("module { \n" - + "}")); - - subst.put("name", "my-module-name"); - subst.put("description", List.of("Description 1.", "Description 2.")); - subst.put("hasdescription", true); - subst.put("header", "/*\n Header Line 1\n Header Line 2\n */\n"); - TypeName typeName = TypeName.create("generator"); - TypeName trigger = TypeName.create("trigger"); - subst.put("generatedanno", helper.generatedStickerFor(typeName, trigger, trigger)); - codegen = helper.applySubstitutions(template, subst, true); - assertThat(codegen, - equalTo("/*\n" - + " Header Line 1\n" - + " Header Line 2\n" - + " */\n" - + "/**\n" - + " * Description 1.\n" - + " * Description 2.\n" - + " */\n" - + "// @io.helidon.common.Generated(value = \"generator\", trigger = \"trigger\")\n" - + "module my-module-name { \n" - + "}\n")); - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/TypeToolsTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/TypeToolsTest.java deleted file mode 100644 index 9dc7544c06a..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/TypeToolsTest.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicReference; - -import io.helidon.common.types.TypeName; - -import io.github.classgraph.ClassInfo; -import io.github.classgraph.FieldInfo; -import io.github.classgraph.MethodParameterInfo; -import io.github.classgraph.ScanResult; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.Test; - -import static io.helidon.common.types.TypeName.create; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -@Named("name") -@SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"}) -public class TypeToolsTest { - ScanResult scan = ReflectionHandler.INSTANCE.scan(); - - ClassInfo ignoredTestClassInfo = Objects.requireNonNull( - scan.getClassInfo(TypeToolsTest.class.getName())); - ClassInfo providerOfGenericClassInfo = Objects.requireNonNull( - scan.getClassInfo(ProviderOfGeneric.class.getName())); - ClassInfo providerOfDirectClassInfo = Objects.requireNonNull( - scan.getClassInfo(ProviderOfTypeDirect.class.getName())); - ClassInfo ignoredProviderOfTypeThroughSuperClassInfo = Objects.requireNonNull( - scan.getClassInfo(ProviderOfTypeThroughSuper.class.getName())); - ClassInfo ignoredInjectionPointProviderOfTypeDirectClassInfo = Objects.requireNonNull( - scan.getClassInfo(InjectionPointProviderOfTypeDirect.class.getName())); - - TypeName typeToolsTestTypeName = create(TypeToolsTest.class); - TypeName stringTypeName = create(String.class); - TypeName booleanTypeName = create(Boolean.class); - - @Test - void optionalsProvidersAndListsOfFieldInfo() { - optionalsProvidersAndLists(typeToolsTestTypeName, true, true, false, - providerOfGenericClassInfo.getFieldInfo("listOfProviders")); - optionalsProvidersAndLists(typeToolsTestTypeName, true, false, true, - providerOfGenericClassInfo.getFieldInfo("optionalProvider")); - optionalsProvidersAndLists(typeToolsTestTypeName, false, false, true, - providerOfGenericClassInfo.getFieldInfo("optionalNotProvider")); - optionalsProvidersAndListsException("Unsupported type for D in abstract static class io.helidon.inject.tools" - + ".TypeToolsTest$ProviderOfGeneric implements jakarta.inject.Provider", - providerOfGenericClassInfo.getFieldInfo("generic")); - optionalsProvidersAndListsException("Unsupported type for D in abstract static class io.helidon.inject.tools" - + ".TypeToolsTest$ProviderOfGeneric implements jakarta.inject.Provider", - providerOfGenericClassInfo.getFieldInfo("listOfProvidersOfGeneric")); - optionalsProvidersAndListsException("Unsupported type for D in abstract static class io.helidon.inject.tools" - + ".TypeToolsTest$ProviderOfGeneric implements jakarta.inject.Provider", - providerOfGenericClassInfo.getFieldInfo("optionalProviderOfGeneric")); - optionalsProvidersAndListsException("Unsupported type for D in abstract static class io.helidon.inject.tools" - + ".TypeToolsTest$ProviderOfGeneric implements jakarta.inject.Provider", - providerOfGenericClassInfo.getFieldInfo("optionalOfGeneric")); - - optionalsProvidersAndLists(stringTypeName, true, false, false, - providerOfDirectClassInfo.getFieldInfo("providerOfString")); - optionalsProvidersAndLists(stringTypeName, true, true, false, - providerOfDirectClassInfo.getFieldInfo("listOfProvidersOfStrings")); - optionalsProvidersAndLists(stringTypeName, true, false, true, - providerOfDirectClassInfo.getFieldInfo("optionalProviderOfString")); - optionalsProvidersAndLists(stringTypeName, false, false, true, - providerOfDirectClassInfo.getFieldInfo("optionalString")); - optionalsProvidersAndLists(stringTypeName, false, false, false, - providerOfDirectClassInfo.getFieldInfo("string")); - - optionalsProvidersAndLists(stringTypeName, true, false, false, - providerOfDirectClassInfo.getFieldInfo("providerOfString")); - optionalsProvidersAndLists(stringTypeName, true, true, false, - providerOfDirectClassInfo.getFieldInfo("listOfProvidersOfStrings")); - optionalsProvidersAndLists(stringTypeName, true, false, true, - providerOfDirectClassInfo.getFieldInfo("optionalProviderOfString")); - optionalsProvidersAndLists(stringTypeName, false, false, true, - providerOfDirectClassInfo.getFieldInfo("optionalString")); - optionalsProvidersAndLists(stringTypeName, false, false, false, - providerOfDirectClassInfo.getFieldInfo("string")); - } - - @Test - void optionalsProvidersAndListsOfMethodParams() { - optionalsProvidersAndLists(typeToolsTestTypeName, true, false, false, - providerOfGenericClassInfo.getMethodInfo("setProvider") - .get(0).getParameterInfo()[0]); - optionalsProvidersAndLists(typeToolsTestTypeName, true, true, false, - providerOfGenericClassInfo.getMethodInfo("setListOfProviders") - .get(0).getParameterInfo()[0]); - optionalsProvidersAndLists(typeToolsTestTypeName, true, false, true, - providerOfGenericClassInfo.getMethodInfo("setOptionalProvider") - .get(0).getParameterInfo()[0]); - optionalsProvidersAndLists(typeToolsTestTypeName, false, false, true, - providerOfGenericClassInfo.getMethodInfo("setOptionalNotProvider") - .get(0).getParameterInfo()[0]); - optionalsProvidersAndLists(typeToolsTestTypeName, false, false, false, - providerOfGenericClassInfo.getMethodInfo("setTyped") - .get(0).getParameterInfo()[0]); - optionalsProvidersAndListsException("Unsupported type for D in public void setGeneric(D)", - providerOfGenericClassInfo.getMethodInfo("setGeneric") - .get(0).getParameterInfo()[0]); - - optionalsProvidersAndLists(stringTypeName, true, false, false, - providerOfDirectClassInfo.getMethodInfo("setProviderOfString") - .get(0).getParameterInfo()[0]); - optionalsProvidersAndLists(stringTypeName, false, false, false, - providerOfDirectClassInfo.getMethodInfo("setString") - .get(0).getParameterInfo()[0]); - } - - private void optionalsProvidersAndLists(TypeName expectedType, - boolean expectedProvider, - boolean expectedList, - boolean expectedOptional, - FieldInfo fld) { - assertNotNull(fld); - AtomicReference isProvider = new AtomicReference<>(); - AtomicReference isList = new AtomicReference<>(); - AtomicReference isOptional = new AtomicReference<>(); - MatcherAssert.assertThat(TypeTools.extractInjectionPointTypeInfo(fld, isProvider, isList, isOptional), equalTo(expectedType)); - assertThat("provider for " + fld, isProvider.get(), is(expectedProvider)); - assertThat("list for " + fld, isList.get(), equalTo(expectedList)); - assertThat("optional for " + fld, isOptional.get(), is(expectedOptional)); - } - - private void optionalsProvidersAndListsException(String exceptedException, - FieldInfo fld) { - AtomicReference isProvider = new AtomicReference<>(); - AtomicReference isList = new AtomicReference<>(); - AtomicReference isOptional = new AtomicReference<>(); - Exception te = assertThrows(IllegalStateException.class, - () -> TypeTools.extractInjectionPointTypeInfo(fld, isProvider, isList, isOptional)); - assertThat(fld.toString(), te.getMessage(), equalTo(exceptedException)); - } - - private void optionalsProvidersAndLists(TypeName expectedType, - boolean expectedProvider, - boolean expectedList, - boolean expectedOptional, - MethodParameterInfo fld) { - AtomicReference isProvider = new AtomicReference<>(); - AtomicReference isList = new AtomicReference<>(); - AtomicReference isOptional = new AtomicReference<>(); - MatcherAssert.assertThat(TypeTools.extractInjectionPointTypeInfo(fld, isProvider, isList, isOptional), equalTo(expectedType)); - assertThat("provider for " + fld, isProvider.get(), is(expectedProvider)); - assertThat("list for " + fld, isList.get(), equalTo(expectedList)); - assertThat("optional for " + fld, isOptional.get(), is(expectedOptional)); - } - - private void optionalsProvidersAndListsException(String exceptedException, - MethodParameterInfo fld) { - AtomicReference isProvider = new AtomicReference<>(); - AtomicReference isList = new AtomicReference<>(); - AtomicReference isOptional = new AtomicReference<>(); - Exception te = assertThrows(IllegalStateException.class, - () -> TypeTools.extractInjectionPointTypeInfo(fld, isProvider, isList, isOptional)); - assertThat(fld.toString(), te.getMessage(), equalTo(exceptedException)); - } - - - static abstract class ProviderOfGeneric implements Provider { - List> listOfProviders; - Optional> optionalProvider; - Optional optionalNotProvider; - D generic; - List> listOfProvidersOfGeneric; - Optional> optionalProviderOfGeneric; - Optional optionalOfGeneric; - - public void setProvider(Provider ignored) { - } - - public void setListOfProviders(List> ignored) { - } - - public void setOptionalProvider(Optional> ignored) { - } - - public void setOptionalNotProvider(Optional ignored) { - } - - public void setTyped(TypeToolsTest ignored) { - } - - public void setGeneric(D ignored) { - } - } - - - static class ProviderOfTypeDirect implements Provider { - Provider providerOfString; - List> listOfProvidersOfStrings; - Optional> optionalProviderOfString; - Optional optionalString; - String string; - - public ProviderOfTypeDirect(Provider provider) { - this.providerOfString = provider; - } - - @Override - public String get() { - return (providerOfString == null) ? null : providerOfString.get(); - } - - void setProviderOfString(Provider provider) { - this.providerOfString = provider; - } - - void setString(String ignored) { - } - } - - static class ProviderOfTypeThroughSuper extends ProviderOfGeneric { - Provider provider; - - public ProviderOfTypeThroughSuper(Provider provider) { - this.provider = provider; - } - - @Override - public Integer get() { - return (provider == null) ? null : provider.get(); - } - } - - static class InjectionPointProviderOfTypeDirect extends ProviderOfGeneric implements Provider { - Provider provider; - - public InjectionPointProviderOfTypeDirect(Provider provider) { - this.provider = provider; - } - - @Override - public Boolean get() { - return (provider == null) ? null : provider.get(); - } - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/HelloInjectionWorld.java b/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/HelloInjectionWorld.java deleted file mode 100644 index 56f06a6d74f..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/HelloInjectionWorld.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.testsubjects; - -import io.helidon.inject.api.Contract; - -/** - * For testing. - */ -@Contract -public interface HelloInjectionWorld { - - /** - * For testing. - * - * @return for testing - */ - String sayHello(); - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/HelloInjectionWorldImpl.java b/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/HelloInjectionWorldImpl.java deleted file mode 100644 index a8de2c0497f..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/HelloInjectionWorldImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.testsubjects; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -import io.helidon.inject.api.RunLevel; - -import jakarta.annotation.PostConstruct; -import jakarta.annotation.PreDestroy; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; - -@Singleton -@RunLevel(0) -@SuppressWarnings("unused") -public class HelloInjectionWorldImpl implements HelloInjectionWorld { - - @Inject - InjectionWorld world; - - @Inject - Provider worldRef; - - @Inject - List> listOfWorldRefs; - - @Inject - List listOfWorlds; - - @Inject @Named("red") - Optional redWorld; - - private InjectionWorld setWorld; - - int postConstructCallCount; - int preDestroyCallCount; - - @Inject - HelloInjectionWorldImpl(InjectionWorld injectionWorld) { - Objects.requireNonNull(injectionWorld); - } - - @Override - public String sayHello() { - assert(postConstructCallCount == 1); - assert(preDestroyCallCount == 0); - assert(world == worldRef.get()); - assert(world == setWorld); - assert(redWorld.isEmpty()); - - return "Hello " + world.name(); - } - - @Inject - void world(InjectionWorld world) { - this.setWorld = world; - } - - @PostConstruct - public void postConstruct() { - postConstructCallCount++; - } - - @PreDestroy - public void preDestroy() { - preDestroyCallCount++; - } - - public int postConstructCallCount() { - return postConstructCallCount; - } - - public int preDestroyCallCount() { - return preDestroyCallCount; - } - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/InjectionWorld.java b/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/InjectionWorld.java deleted file mode 100644 index 2ad1996fb2b..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/InjectionWorld.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.testsubjects; - -/** - * For testing. - */ -// @Contract - we will test ExternalContracts here instead -public interface InjectionWorld { - - /** - * For testing. - * - * @return for testing - */ - String name(); - -} diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/InjectionWorldImpl.java b/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/InjectionWorldImpl.java deleted file mode 100644 index e9d28bb91a2..00000000000 --- a/inject/tools/src/test/java/io/helidon/inject/tools/testsubjects/InjectionWorldImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.inject.tools.testsubjects; - -import io.helidon.inject.api.ExternalContracts; - -@ExternalContracts(InjectionWorld.class) -public class InjectionWorldImpl implements InjectionWorld { - private final String name; - - InjectionWorldImpl() { - this("inject"); - } - - InjectionWorldImpl(String name) { - this.name = name; - } - - @Override - public String name() { - return name; - } - -} diff --git a/inject/tools/src/test/resources/testsubjects/m0._java_ b/inject/tools/src/test/resources/testsubjects/m0._java_ deleted file mode 100644 index bbda04d46ed..00000000000 --- a/inject/tools/src/test/resources/testsubjects/m0._java_ +++ /dev/null @@ -1,19 +0,0 @@ -module io.helidon.inject { - - requires transitive io.helidon.inject.api; - requires static com.fasterxml.jackson.annotation; - requires static lombok; - requires io.helidon.common; - - exports io.helidon.inject.spi.impl; - - provides io.helidon.inject.api.InjectionServices with io.helidon.inject.spi.impl.DefaultInjectionServices; - - uses io.helidon.inject.api.ModuleComponent; - uses io.helidon.inject.api.Application; - - // needed when running with modules - to make private methods accessible - // another comment with a semicolon; - opens io.helidon.config to weld.core.impl, - io.helidon.microprofile.cdi; -} diff --git a/integrations/oci/sdk/README.md b/integrations/oci/sdk/README.md index 217b888e94b..39efa5e7de8 100644 --- a/integrations/oci/sdk/README.md +++ b/integrations/oci/sdk/README.md @@ -4,12 +4,12 @@ There are two different approaches for [OCI SDK](https://docs.oracle.com/en-us/i * **Helidon MP** (using _CDI_). For this refer to the [cdi](./cdi) module. * **Helidon SE** (not using _CDI_). For this refer to the information below. -## Helidon Injection Framework and OCI SDK Integration -This section only applies for **Helidon SE** type applications. If you are using **Helidon MP** then this section does not apply to you, and you should instead refer to the [cdi](./cdi) module. If you are using **Helidon SE** then continue reading below. Please familiarize yourself with the basics of the [Helidon Injection Framework](../../../inject) and terminology before continuing further. +## Helidon Service Registry and OCI SDK Integration +This section only applies for **Helidon SE** type applications. If you are using **Helidon MP** then this section does not apply to you, and you should instead refer to the [cdi](./cdi) module. If you are using **Helidon SE** then continue reading below. Please familiarize yourself with the basics of the [Helidon Service Registry](../../../service) and terminology before continuing further. -The **Helidon Injection Framework** offers two modules for integrating with the **OCI SDK API** - the _processor_ module and the _runtime_ module. +The **Helidon Service Registry** offers two modules for integrating with the **OCI SDK API** - the _codegen_ module and the _runtime_ module. -1. The [processor](./processor) module is required to be on your compiler / annotation processor [APT] classpath. It is not needed at runtime, however. When used on the compiler / APT classpath, it will observe cases where your application uses the _@Inject_ annotation on API services from the **OCI SDK**. When it finds such cases, it generates source code defining an _Activator_ representing the API service you are injecting. These generated _Activator_ will then be used by the **Helidon Injection Framework** at runtime. +1. The [codegen](./codegen) module is required to be on your annotation processor [APT] classpath. It is not needed at runtime, however. When used on the APT classpath, it will observe cases where your application uses the _@Service.Inject_ annotation on API services from the **OCI SDK**. When it finds such cases, it generates service source code representing the API service you are injecting. These generated _Services_ will then be used by the **Helidon Service Registry** at runtime. 2. The [runtime](./runtime) module is required to be on your runtime classpath, but is not needed at compile time. This module supplies the default implementation for OCI's authentication providers, as well as other OCI extensibility classes (see the [javadoc](./runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/package-info.java) for details). @@ -32,14 +32,18 @@ In your pom.xml, add this plugin to be run as part of the compilation phase: org.apache.maven.plugins maven-compiler-plugin - true - - - io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-processor - ${helidon.version} - - + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.integrations.oci.sdk + helidon-integrations-oci-sdk-codegen + ${helidon.version} + + ``` diff --git a/integrations/oci/sdk/processor/README.md b/integrations/oci/sdk/codegen/README.md similarity index 61% rename from integrations/oci/sdk/processor/README.md rename to integrations/oci/sdk/codegen/README.md index f3f62d15368..3be34dbd740 100644 --- a/integrations/oci/sdk/processor/README.md +++ b/integrations/oci/sdk/codegen/README.md @@ -1,3 +1,3 @@ -# helidon-integrations-oci-sdk-processor +# helidon-integrations-oci-sdk-codegen Refer to the [helidon-integrations-oci-sdk](../) documentation. diff --git a/integrations/oci/sdk/processor/pom.xml b/integrations/oci/sdk/codegen/pom.xml similarity index 67% rename from integrations/oci/sdk/processor/pom.xml rename to integrations/oci/sdk/codegen/pom.xml index 14a63e8b9b3..3c2f1e53ee6 100644 --- a/integrations/oci/sdk/processor/pom.xml +++ b/integrations/oci/sdk/codegen/pom.xml @@ -1,7 +1,7 @@ - io.helidon.integrations.oci.sdk helidon-integrations-oci-sdk-project 4.2.0-SNAPSHOT + ../pom.xml 4.0.0 - helidon-integrations-oci-sdk-processor - Helidon Integrations OCI Injection Processor + helidon-integrations-oci-sdk-codegen + Helidon Integrations OCI Injection Codegen - Helidon Injection Framework APT support for the OCI SDK + Helidon Service Registry Code generation support for the OCI SDK - io.helidon.inject - helidon-inject-processor + io.helidon.codegen + helidon-codegen-apt - com.github.jknack - handlebars + io.helidon.codegen + helidon-codegen-class-model - - org.slf4j - slf4j-api - - - org.slf4j - slf4j-jdk14 + io.helidon.service + helidon-service-codegen io.helidon.common.testing helidon-common-testing-junit5 test + + io.helidon.codegen + helidon-codegen-helidon-copyright + test + org.hamcrest hamcrest-all @@ -91,4 +92,15 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + -proc:none + + + + diff --git a/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/OciInjectCodegenObserverProvider.java b/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/OciInjectCodegenObserverProvider.java new file mode 100644 index 00000000000..211d68bd584 --- /dev/null +++ b/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/OciInjectCodegenObserverProvider.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.integrations.oci.sdk.codegen; + +import java.util.Set; +import java.util.function.Function; + +import io.helidon.codegen.Option; +import io.helidon.common.GenericType; +import io.helidon.service.codegen.RegistryCodegenContext; +import io.helidon.service.codegen.spi.InjectCodegenObserver; +import io.helidon.service.codegen.spi.InjectCodegenObserverProvider; + +/** + * A {@link java.util.ServiceLoader} provider implementation + * for {@link io.helidon.service.codegen.spi.InjectCodegenObserverProvider} that creates an observer + * watching for injections of OCI types, and that generates appropriate services for them. + */ +public class OciInjectCodegenObserverProvider implements InjectCodegenObserverProvider { + static final Option> OPTION_TYPENAME_EXCEPTIONS = + Option.createSet("inject.oci.codegenExclusions", + "Set of type to exclude from generation", + Set.of(), + Function.identity(), + new GenericType>() { }); + static final Option> OPTION_NO_DOT_EXCEPTIONS = + Option.createSet("inject.oci.builderNameExceptions", + "Set of types that do not use a dot between type and builder.", + Set.of(), + Function.identity(), + new GenericType>() { }); + + /** + * Service loader based constructor. + * + * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly + */ + @Deprecated + public OciInjectCodegenObserverProvider() { + } + + @Override + public InjectCodegenObserver create(RegistryCodegenContext context) { + return new OciInjectionCodegenObserver(context); + } + + @Override + public Set> supportedOptions() { + return Set.of(OPTION_NO_DOT_EXCEPTIONS, + OPTION_TYPENAME_EXCEPTIONS); + } +} diff --git a/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/OciInjectionCodegenObserver.java b/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/OciInjectionCodegenObserver.java new file mode 100644 index 00000000000..f94934bea58 --- /dev/null +++ b/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/OciInjectionCodegenObserver.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2025 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.integrations.oci.sdk.codegen; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import io.helidon.codegen.CodegenException; +import io.helidon.codegen.CodegenOptions; +import io.helidon.codegen.CodegenUtil; +import io.helidon.codegen.classmodel.ClassModel; +import io.helidon.common.Weight; +import io.helidon.common.Weighted; +import io.helidon.common.types.AccessModifier; +import io.helidon.common.types.Annotation; +import io.helidon.common.types.Annotations; +import io.helidon.common.types.TypeName; +import io.helidon.common.types.TypeNames; +import io.helidon.common.types.TypedElementInfo; +import io.helidon.service.codegen.RegistryCodegenContext; +import io.helidon.service.codegen.RegistryRoundContext; +import io.helidon.service.codegen.ServiceCodegenTypes; +import io.helidon.service.codegen.spi.InjectCodegenObserver; + +import static io.helidon.service.codegen.ServiceCodegenTypes.SERVICE_QUALIFIED_INSTANCE; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.function.Predicate.not; + +/** + * This processor is an implementation of {@link io.helidon.service.codegen.spi.InjectCodegenObserver}. + * When on the APT classpath, it will monitor + * injection processor for all injection points that are + * using the {@code OCI SDK Services} and translate those injection points into code-generated + * {@code ServiceDescriptors}s, {@code ModuleComponent}, etc. for those services / components. + * This process will therefore make the {@code OCI SDK} set of services injectable by your (non-MP-based) Helidon application, and + * be tailored to exactly what is actually used by your application from the SDK. + *

+ * For example, if your code had this: + *

+ * {@code
+ *   @Inject
+ *   com.oracle.bmc.ObjectStorage objStore;
+ * }
+ * 
+ * This would result in code generating the necessary artifacts at compile time that will make {@code ObjectStorage} injectable. + *

+ * All injection points using the same package name as the OCI SDK (e.g., {@code com.oracle.bmc} as shown with ObjectStorage in + * the case above) will be observed and processed and eventually result in code generation into your + * {@code target/generated-sources} directory. This is the case for any artifact that is attempted to be injected unless there is + * found a configuration signaling an exception to avoid the code generation for the activator. + *

+ * The processor will allow exceptions in one of three ways: + *

    + *
  • via the code directly here - see the {@link #shouldProcess} method.
  • + *
  • via resources on the classpath - the implementation looks for files named {@link #TYPENAME_EXCEPTIONS_FILENAME} + * in {@code META-INF/helidon/oci/sdk/codegen}, and will read those resources during initialization. + * Each line of this file would be a fully qualified type name to avoid processing that type name.
  • + *
  • via {@code -A} directives on the compiler command line. Using the same tag as referenced above. The line can be + * comma-delimited, and each token will be treated as a fully qualified type name to signal that the type should be + * not be processed.
  • + *
+ */ +class OciInjectionCodegenObserver implements InjectCodegenObserver { + static final String OCI_ROOT_PACKAGE_NAME_PREFIX = "com.oracle.bmc."; + + // all generated sources will have this package prefix + static final String GENERATED_PREFIX = "io.helidon.integrations.generated."; + // all generated sources will have this class name suffix + static final String GENERATED_CLIENT_SUFFIX = "__Oci_Client"; + static final String GENERATED_CLIENT_BUILDER_SUFFIX = GENERATED_CLIENT_SUFFIX + "Builder"; + private static final double DEFAULT_INJECT_WEIGHT = Weighted.DEFAULT_WEIGHT - 1; + private static final TypeName PROCESSOR_TYPE = TypeName.create(OciInjectionCodegenObserver.class); + private static final String TYPENAME_EXCEPTIONS_FILENAME = "codegen-exclusions.txt"; + private static final String NO_DOT_EXCEPTIONS_FILENAME = "builder-name-exceptions.txt"; + private static final Set FACTORIES = Set.of( + TypeNames.SUPPLIER, + ServiceCodegenTypes.SERVICE_SERVICES_FACTORY, + ServiceCodegenTypes.SERVICE_INJECTION_POINT_FACTORY, + ServiceCodegenTypes.SERVICE_QUALIFIED_FACTORY); + + private final Set typenameExceptions; + private final Set noDotExceptions; + private final RegistryCodegenContext ctx; + + OciInjectionCodegenObserver(RegistryCodegenContext ctx) { + this.ctx = ctx; + + CodegenOptions options = ctx.options(); + + Set typenameExceptions = new HashSet<>(); + typenameExceptions.addAll(OciInjectCodegenObserverProvider.OPTION_TYPENAME_EXCEPTIONS.value(options)); + typenameExceptions.addAll(loadMetaConfig(TYPENAME_EXCEPTIONS_FILENAME)); + this.typenameExceptions = typenameExceptions; + + Set noDotExceptions = new HashSet<>(); + noDotExceptions.addAll(OciInjectCodegenObserverProvider.OPTION_NO_DOT_EXCEPTIONS.value(options)); + noDotExceptions.addAll(loadMetaConfig(NO_DOT_EXCEPTIONS_FILENAME)); + this.noDotExceptions = noDotExceptions; + } + + static TypeName toGeneratedServiceClientTypeName(TypeName typeName) { + return TypeName.builder() + .packageName(GENERATED_PREFIX + typeName.packageName()) + .className(typeName.className() + GENERATED_CLIENT_SUFFIX) + .build(); + } + + static TypeName toGeneratedServiceClientBuilderTypeName(TypeName typeName) { + return TypeName.builder() + .packageName(GENERATED_PREFIX + typeName.packageName()) + .className(typeName.className() + GENERATED_CLIENT_BUILDER_SUFFIX) + .build(); + } + + @Override + public void onProcessingEvent(RegistryRoundContext roundContext, Set elements) { + elements.stream() + .filter(this::shouldProcess) + .forEach(it -> process(roundContext, it)); + } + + Set typenameExceptions() { + return typenameExceptions; + } + + Set noDotExceptions() { + return noDotExceptions; + } + + ClassModel.Builder toBuilderBody(TypeName ociServiceTypeName, + TypeName generatedOciService, + TypeName generatedOciServiceBuilderTypeName) { + boolean usesRegion = usesRegion(ociServiceTypeName); + + String maybeDot = maybeDot(ociServiceTypeName); + String builderSuffix = "Client" + maybeDot + "Builder"; + + ClassModel.Builder classModel = ClassModel.builder() + .accessModifier(AccessModifier.PACKAGE_PRIVATE) + .copyright(CodegenUtil.copyright(PROCESSOR_TYPE, + ociServiceTypeName, + generatedOciService)) + .addAnnotation(CodegenUtil.generatedAnnotation(PROCESSOR_TYPE, + ociServiceTypeName, + generatedOciService, + "1", + "")) + .type(generatedOciServiceBuilderTypeName) + .addInterface(ipProvider(ociServiceTypeName, builderSuffix)) + .addAnnotation(Annotation.create(ServiceCodegenTypes.SERVICE_ANNOTATION_SINGLETON)) + .addAnnotation(Annotation.builder() + .typeName(TypeName.create(Weight.class)) + .putValue("value", DEFAULT_INJECT_WEIGHT) + .build()); + + // fields + if (usesRegion) { + TypeName regionProviderType = ipProvider(TypeName.create("com.oracle.bmc.Region"), ""); + classModel.addField(regionProvider -> regionProvider + .isFinal(true) + .accessModifier(AccessModifier.PRIVATE) + .name("regionProvider") + .type(regionProviderType)); + // constructor + classModel.addConstructor(ctor -> ctor + .accessModifier(AccessModifier.PACKAGE_PRIVATE) + .addAnnotation(Annotation.create(ServiceCodegenTypes.SERVICE_ANNOTATION_INJECT)) + .addAnnotation(Annotation.create(Deprecated.class)) + .addParameter(regionProvider -> regionProvider.name("regionProvider") + .type(regionProviderType)) + .addContentLine("this.regionProvider = regionProvider;")); + } else { + // constructor + classModel.addConstructor(ctor -> ctor + .accessModifier(AccessModifier.PACKAGE_PRIVATE) + .addAnnotation(Annotation.create(ServiceCodegenTypes.SERVICE_ANNOTATION_INJECT)) + .addAnnotation(Annotation.create(Deprecated.class))); + } + + String clientType = "@" + ociServiceTypeName.fqName() + "Client@"; + + // method(s) + classModel.addMethod(first -> first + .name("first") + .addAnnotation(Annotation.create(Override.class)) + .returnType(optionalQualifiedInstance(ociServiceTypeName, builderSuffix)) + .addParameter(query -> query.name("query") + .type(ServiceCodegenTypes.SERVICE_LOOKUP)) + .update(it -> { + if (usesRegion) { + it.addContentLine("var builder = " + clientType + ".builder();") + .addContent("regionProvider.first(query).map(") + .addContent(SERVICE_QUALIFIED_INSTANCE) + .addContentLine("::get).ifPresent(builder::region);") + .addContent("return ") + .addContent(Optional.class) + .addContent(".of(") + .addContent(SERVICE_QUALIFIED_INSTANCE) + .addContent(".create(") + .addContentLine("builder));"); + } else { + it.addContent("return ") + .addContent(Optional.class) + .addContent(".of(") + .addContent(SERVICE_QUALIFIED_INSTANCE) + .addContent(".create(") + .addContent(clientType) + .addContent(".builder());"); + } + })); + + return classModel; + } + + ClassModel.Builder toBody(TypeName ociServiceTypeName, + TypeName generatedOciService) { + ClassModel.Builder classModel = ClassModel.builder() + .accessModifier(AccessModifier.PACKAGE_PRIVATE) + .copyright(CodegenUtil.copyright(PROCESSOR_TYPE, + ociServiceTypeName, + generatedOciService)) + .addAnnotation(CodegenUtil.generatedAnnotation(PROCESSOR_TYPE, + ociServiceTypeName, + generatedOciService, + "1", + "")) + .type(generatedOciService) + .addInterface(ipProvider(ociServiceTypeName, "Client")) + .addAnnotation(Annotation.create(ServiceCodegenTypes.SERVICE_ANNOTATION_SINGLETON)) + .addAnnotation(Annotation.builder() + .typeName(TypeName.create(Weight.class)) + .putValue("value", DEFAULT_INJECT_WEIGHT) + .build()) + .addAnnotation(Annotation.builder() + .typeName(ServiceCodegenTypes.SERVICE_ANNOTATION_EXTERNAL_CONTRACTS) + .putValue("value", ociServiceTypeName) + .build()); + + TypeName authProviderType = ipProvider(TypeName.create("com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider"), ""); + TypeName builderProviderType = ipProvider(ociServiceTypeName, "Client" + maybeDot(ociServiceTypeName) + "Builder"); + + // fields + classModel.addField(authProvider -> authProvider + .isFinal(true) + .accessModifier(AccessModifier.PRIVATE) + .name("authProvider") + .type(authProviderType)); + + classModel.addField(builderProvider -> builderProvider + .isFinal(true) + .accessModifier(AccessModifier.PRIVATE) + .name("builderProvider") + .type(builderProviderType)); + + // constructor + classModel.addConstructor(ctor -> ctor + .accessModifier(AccessModifier.PACKAGE_PRIVATE) + .addAnnotation(Annotation.create(ServiceCodegenTypes.SERVICE_ANNOTATION_INJECT)) + .addAnnotation(Annotations.DEPRECATED) + .addParameter(authProvider -> authProvider.name("authProvider") + .type(authProviderType)) + .addParameter(builderProvider -> builderProvider.name("builderProvider") + .type(builderProviderType)) + .addContentLine("this.authProvider = authProvider;") + .addContentLine("this.builderProvider = builderProvider;")); + + // method(s) + classModel.addMethod(first -> first + .name("first") + .addAnnotation(Annotation.create(Override.class)) + .returnType(optionalQualifiedInstance(ociServiceTypeName, "Client")) + .addParameter(query -> query.name("query") + .type(ServiceCodegenTypes.SERVICE_LOOKUP)) + .addContent("return ") + .addContent(Optional.class) + .addContent(".of(") + .addContent(SERVICE_QUALIFIED_INSTANCE) + .addContent(".create(") + .addContentLine("builderProvider.first(query).orElseThrow().get().build(authProvider.first" + + "(query).orElseThrow().get())));")); + + return classModel; + } + + boolean usesRegion(TypeName ociServiceTypeName) { + // it turns out that the same exceptions used for dotting the builder also applies to whether it uses region + return !noDotExceptions.contains(ociServiceTypeName.name()); + } + + String maybeDot(TypeName ociServiceTypeName) { + return noDotExceptions.contains(ociServiceTypeName.name()) ? "" : "."; + } + + boolean shouldProcess(TypeName typeName) { + if (!typeName.typeArguments().isEmpty() + && isFactory(typeName) || typeName.isOptional()) { + typeName = typeName.typeArguments().getFirst(); + } + + String name = typeName.resolvedName(); + if (!name.startsWith(OCI_ROOT_PACKAGE_NAME_PREFIX) + || name.endsWith(".Builder") + || name.endsWith("Client") + || name.endsWith("ClientBuilder") + || typenameExceptions.contains(name)) { + return false; + } + + // check to see if we already generated it before, and if so we can skip creating it again + TypeName generatedTypeName = toGeneratedServiceClientTypeName(typeName); + return ctx.typeInfo(generatedTypeName).isEmpty(); + } + + private boolean isFactory(TypeName typeName) { + return FACTORIES.contains(typeName); + } + + private static Set loadMetaConfig(String fileName) { + String path = "META-INF/helidon/oci/sdk/codegen/" + fileName; + + Set result = new HashSet<>(); + try { + Enumeration resources = OciInjectionCodegenObserver.class.getClassLoader().getResources(path); + while (resources.hasMoreElements()) { + URL url = resources.nextElement(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) { + reader.lines() + .map(String::trim) // trim to text + .filter(not(String::isEmpty)) // filter empty lines + .filter(not(s -> s.startsWith("#"))) // ignore comments + .forEach(result::add); + } + } + } catch (IOException e) { + throw new CodegenException("Failed to load " + path + " from classpath", e); + } + return result; + } + + private static TypeName optionalQualifiedInstance(TypeName typeName, String suffix) { + return TypeName.builder(io.helidon.common.types.TypeNames.OPTIONAL) + .addTypeArgument(TypeName.builder(SERVICE_QUALIFIED_INSTANCE) + .addTypeArgument(TypeName.create(typeName.fqName() + suffix)) + .build()) + .build(); + } + + private static TypeName ipProvider(TypeName provided, String suffix) { + return TypeName.builder(ServiceCodegenTypes.SERVICE_INJECTION_POINT_FACTORY) + .addTypeArgument(TypeName.create(provided.fqName() + suffix)) + .build(); + } + + private boolean shouldProcess(TypedElementInfo element) { + if (!element.hasAnnotation(ServiceCodegenTypes.SERVICE_ANNOTATION_INJECT)) { + return false; + } + + return switch (element.kind()) { + case FIELD -> shouldProcess(element.typeName()); + case METHOD, CONSTRUCTOR -> element.parameterArguments().stream() + .anyMatch(it -> shouldProcess(it.typeName())); + default -> false; + }; + } + + private void process(RegistryRoundContext roundCtx, TypedElementInfo element) { + switch (element.kind()) { + case FIELD -> process(roundCtx, element.typeName()); + case METHOD, CONSTRUCTOR -> element.parameterArguments().stream() + .filter(it -> shouldProcess(it.typeName())) + .forEach(it -> process(roundCtx, it.typeName())); + default -> { + } + } + } + + private void process(RegistryRoundContext roundCtx, TypeName ociServiceTypeName) { + if (isFactory(ociServiceTypeName) + || ociServiceTypeName.isOptional()) { + ociServiceTypeName = ociServiceTypeName.typeArguments().getFirst(); + } + assert (!ociServiceTypeName.generic()) : ociServiceTypeName.name(); + assert (ociServiceTypeName.name().startsWith(OCI_ROOT_PACKAGE_NAME_PREFIX)) : ociServiceTypeName.name(); + + TypeName generatedOciServiceClientTypeName = toGeneratedServiceClientTypeName(ociServiceTypeName); + if (roundCtx.generatedType(generatedOciServiceClientTypeName).isEmpty()) { + // only code generate once + ClassModel.Builder serviceClient = toBody(ociServiceTypeName, + generatedOciServiceClientTypeName); + roundCtx.addGeneratedType(generatedOciServiceClientTypeName, serviceClient, ociServiceTypeName); + } + + TypeName generatedOciServiceClientBuilderTypeName = toGeneratedServiceClientBuilderTypeName(ociServiceTypeName); + if (roundCtx.generatedType(generatedOciServiceClientBuilderTypeName).isEmpty()) { + // only code generate once + ClassModel.Builder serviceClientBuilder = toBuilderBody(ociServiceTypeName, + generatedOciServiceClientTypeName, + generatedOciServiceClientBuilderTypeName); + roundCtx.addGeneratedType(generatedOciServiceClientBuilderTypeName, serviceClientBuilder, ociServiceTypeName); + } + } +} diff --git a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ClassNamedX.java b/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/package-info.java similarity index 77% rename from inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ClassNamedX.java rename to integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/package-info.java index e3351d10689..dbcd23ae7fe 100644 --- a/inject/tests/resources-inject/src/main/java/io/helidon/inject/tests/inject/ClassNamedX.java +++ b/integrations/oci/sdk/codegen/src/main/java/io/helidon/integrations/oci/sdk/codegen/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,10 +14,7 @@ * limitations under the License. */ -package io.helidon.inject.tests.inject; - /** - * For Testing. + * Code generation for Helidon Service Registry for the OCI SDK. */ -public class ClassNamedX { -} +package io.helidon.integrations.oci.sdk.codegen; diff --git a/inject/api/src/main/java/io/helidon/inject/api/Event.java b/integrations/oci/sdk/codegen/src/main/java/module-info.java similarity index 50% rename from inject/api/src/main/java/io/helidon/inject/api/Event.java rename to integrations/oci/sdk/codegen/src/main/java/module-info.java index 8fceb7aff80..0e81ea27df1 100644 --- a/inject/api/src/main/java/io/helidon/inject/api/Event.java +++ b/integrations/oci/sdk/codegen/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,28 +14,19 @@ * limitations under the License. */ -package io.helidon.inject.api; - /** - * A lifecycle activation event. - * @deprecated Helidon inject is deprecated and will be replaced in a future version + * Code generation for Helidon Service Registry for the OCI SDK. */ -@Deprecated(forRemoval = true, since = "4.0.8") -public enum Event { +module io.helidon.integrations.oci.sdk.codegen { + requires io.helidon.codegen; + requires io.helidon.codegen.classmodel; - /** - * Starting. - */ - STARTING, + requires transitive io.helidon.common.types; + requires transitive io.helidon.service.codegen; - /** - * Finished. - */ - FINISHED, + exports io.helidon.integrations.oci.sdk.codegen; - /** - * Other, informational. - */ - OTHER + provides io.helidon.service.codegen.spi.InjectCodegenObserverProvider + with io.helidon.integrations.oci.sdk.codegen.OciInjectCodegenObserverProvider; } diff --git a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/builder-name-exceptions.txt b/integrations/oci/sdk/codegen/src/main/resources/META-INF/helidon/oci/sdk/codegen/builder-name-exceptions.txt similarity index 86% rename from integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/builder-name-exceptions.txt rename to integrations/oci/sdk/codegen/src/main/resources/META-INF/helidon/oci/sdk/codegen/builder-name-exceptions.txt index 19aac9b165f..e1ae7f5cb84 100644 --- a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/builder-name-exceptions.txt +++ b/integrations/oci/sdk/codegen/src/main/resources/META-INF/helidon/oci/sdk/codegen/builder-name-exceptions.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. +# Copyright (c) 2023, 2024 Oracle and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ # limitations under the License. # -# these classes do not follow the normal dotted names for the Client Builder - see `{{dot}}` in the hbs template files +# these classes do not follow the normal dotted names for the Client Builder com.oracle.bmc.streaming.Stream com.oracle.bmc.streaming.StreamAsync diff --git a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/codegen-exclusions.txt b/integrations/oci/sdk/codegen/src/main/resources/META-INF/helidon/oci/sdk/codegen/codegen-exclusions.txt similarity index 93% rename from integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/codegen-exclusions.txt rename to integrations/oci/sdk/codegen/src/main/resources/META-INF/helidon/oci/sdk/codegen/codegen-exclusions.txt index e42f64c50ee..76596e0b194 100644 --- a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/codegen-exclusions.txt +++ b/integrations/oci/sdk/codegen/src/main/resources/META-INF/helidon/oci/sdk/codegen/codegen-exclusions.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. +# Copyright (c) 2023, 2024 Oracle and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/integrations/oci/sdk/codegen/src/test/java/io/helidon/integrations/oci/sdk/codegen/OciInjectionProcessorObserverTest.java b/integrations/oci/sdk/codegen/src/test/java/io/helidon/integrations/oci/sdk/codegen/OciInjectionProcessorObserverTest.java new file mode 100644 index 00000000000..f6928091011 --- /dev/null +++ b/integrations/oci/sdk/codegen/src/test/java/io/helidon/integrations/oci/sdk/codegen/OciInjectionProcessorObserverTest.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.integrations.oci.sdk.codegen; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.Calendar; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import io.helidon.codegen.CodegenException; +import io.helidon.codegen.CodegenFiler; +import io.helidon.codegen.CodegenLogger; +import io.helidon.codegen.CodegenOptions; +import io.helidon.codegen.CodegenScope; +import io.helidon.codegen.ModuleInfo; +import io.helidon.codegen.Option; +import io.helidon.codegen.classmodel.ClassModel; +import io.helidon.codegen.spi.AnnotationMapper; +import io.helidon.codegen.spi.ElementMapper; +import io.helidon.codegen.spi.TypeMapper; +import io.helidon.common.types.TypeInfo; +import io.helidon.common.types.TypeName; +import io.helidon.common.types.TypedElementInfo; +import io.helidon.service.codegen.RegistryCodegenContext; + +import com.oracle.bmc.objectstorage.ObjectStorage; +import com.oracle.bmc.streaming.Stream; +import com.oracle.bmc.streaming.StreamAdmin; +import com.oracle.bmc.streaming.StreamAsync; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; + +class OciInjectionProcessorObserverTest { + private static OciInjectionCodegenObserver observer; + + @BeforeAll + static void initTest() { + observer = new OciInjectionCodegenObserver(new TestCodegenContext()); + } + + @Test + void generatedInjectionArtifactsForTypicalOciServices() throws IOException { + TypeName ociServiceType = TypeName.create(ObjectStorage.class); + + TypeName generatedOciServiceClientTypeName = + OciInjectionCodegenObserver.toGeneratedServiceClientTypeName(ociServiceType); + assertThat(generatedOciServiceClientTypeName.name(), + equalTo("io.helidon.integrations.generated." + ociServiceType.name() + "__Oci_Client")); + + ClassModel classModel = observer.toBody(ociServiceType, + generatedOciServiceClientTypeName) + .build(); + + StringWriter sw = new StringWriter(); + classModel.write(sw); + String stringBody = sw.toString(); + assertThat(stringBody.trim(), + equalTo(loadStringFromResource("expected/Objectstorage__Oci_Client._java_"))); + + TypeName generatedOciServiceClientBuilderTypeName = OciInjectionCodegenObserver.toGeneratedServiceClientBuilderTypeName( + ociServiceType); + assertThat(generatedOciServiceClientBuilderTypeName.name(), + equalTo("io.helidon.integrations.generated." + ociServiceType.name() + "__Oci_ClientBuilder")); + + classModel = observer.toBuilderBody(ociServiceType, + generatedOciServiceClientTypeName, + generatedOciServiceClientBuilderTypeName) + .build(); + sw = new StringWriter(); + classModel.write(sw); + stringBody = sw.toString(); + assertThat(stringBody.trim(), + equalTo(loadStringFromResource("expected/Objectstorage__Oci_ClientBuilder._java_"))); + } + + @Test + void oddballServiceTypeNames() { + TypeName ociServiceType = TypeName.create(Stream.class); + assertThat(observer.maybeDot(ociServiceType), + equalTo("")); + assertThat(observer.usesRegion(ociServiceType), + equalTo(false)); + + ociServiceType = TypeName.create(StreamAsync.class); + assertThat(observer.maybeDot(ociServiceType), + equalTo("")); + assertThat(observer.usesRegion(ociServiceType), + equalTo(false)); + + ociServiceType = TypeName.create(StreamAdmin.class); + assertThat(observer.maybeDot(ociServiceType), + equalTo(".")); + assertThat(observer.usesRegion(ociServiceType), + equalTo(true)); + } + + @Test + void testShouldProcess() { + TypeName typeName = TypeName.create(ObjectStorage.class); + assertThat(observer.shouldProcess(typeName), + is(true)); + + typeName = TypeName.create("com.oracle.bmc.circuitbreaker.OciCircuitBreaker"); + assertThat(observer.shouldProcess(typeName), + is(false)); + + typeName = TypeName.create("com.oracle.another.Service"); + assertThat(observer.shouldProcess(typeName), + is(false)); + + typeName = TypeName.create("com.oracle.bmc.Service"); + assertThat(observer.shouldProcess(typeName), + is(true)); + + typeName = TypeName.create("com.oracle.bmc.ServiceClient"); + assertThat(observer.shouldProcess(typeName), + is(false)); + + typeName = TypeName.create("com.oracle.bmc.ServiceClientBuilder"); + assertThat(observer.shouldProcess(typeName), + is(false)); + } + + @Test + void loadTypeNameExceptions() { + Map options = Map.of(OciInjectCodegenObserverProvider.OPTION_TYPENAME_EXCEPTIONS.name(), + "M1, M2"); + OciInjectionCodegenObserver observer = new OciInjectionCodegenObserver(new TestCodegenContext(options)); + + assertThat(observer.typenameExceptions(), + containsInAnyOrder("M1", + "M2", + "test1", + "com.oracle.bmc.Region", + "com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider", + "com.oracle.bmc.circuitbreaker.OciCircuitBreaker" + )); + } + + @Test + void loadNoDotExceptions() { + Map options = Map.of(OciInjectCodegenObserverProvider.OPTION_NO_DOT_EXCEPTIONS.name(), + "Manual1, Manual2 "); + OciInjectionCodegenObserver observer = new OciInjectionCodegenObserver(new TestCodegenContext(options)); + + assertThat(observer.noDotExceptions(), + containsInAnyOrder("Manual1", + "Manual2", + "test2", + "com.oracle.bmc.streaming.Stream", + "com.oracle.bmc.streaming.StreamAsync" + )); + } + + private static String loadStringFromResource(String resourceNamePath) { + try { + try (InputStream in = OciInjectionProcessorObserverTest.class.getClassLoader() + .getResourceAsStream(resourceNamePath)) { + String result = new String(in.readAllBytes(), StandardCharsets.UTF_8).trim(); + return result.replaceAll("\\{\\{YEAR}}", String.valueOf(Calendar.getInstance().get(Calendar.YEAR))) + .trim(); // remove leading and trailing whitespaces + } + } catch (Exception e) { + throw new CodegenException("Failed to load: " + resourceNamePath, e); + } + } + + private static class TestCodegenContext implements RegistryCodegenContext { + private final Map options; + + TestCodegenContext() { + this(Map.of()); + } + + TestCodegenContext(Map options) { + this.options = options; + } + + @Override + public Optional module() { + return Optional.empty(); + } + + @Override + public CodegenFiler filer() { + return null; + } + + @Override + public CodegenLogger logger() { + return null; + } + + @Override + public CodegenScope scope() { + return null; + } + + @Override + public CodegenOptions options() { + return option -> Optional.ofNullable(options.get(option)).map(String::trim); + } + + @Override + public Optional typeInfo(TypeName typeName) { + return Optional.empty(); + } + + @Override + public Optional typeInfo(TypeName typeName, Predicate elementPredicate) { + return Optional.empty(); + } + + @Override + public List elementMappers() { + return null; + } + + @Override + public List typeMappers() { + return null; + } + + @Override + public List annotationMappers() { + return null; + } + + @Override + public Set mapperSupportedAnnotations() { + return null; + } + + @Override + public Set mapperSupportedAnnotationPackages() { + return null; + } + + @Override + public Set> supportedOptions() { + return null; + } + + @Override + public TypeName descriptorType(TypeName serviceType) { + return null; + } + + @Override + public String uniqueName(TypeInfo type, TypedElementInfo element) { + return element.elementName(); + } + } +} diff --git a/integrations/oci/sdk/processor/src/test/resources/io/helidon/integrations/oci/sdk/processor/builder-name-exceptions.txt b/integrations/oci/sdk/codegen/src/test/resources/META-INF/helidon/oci/sdk/codegen/builder-name-exceptions.txt similarity index 90% rename from integrations/oci/sdk/processor/src/test/resources/io/helidon/integrations/oci/sdk/processor/builder-name-exceptions.txt rename to integrations/oci/sdk/codegen/src/test/resources/META-INF/helidon/oci/sdk/codegen/builder-name-exceptions.txt index 43a7bfd19f0..9141b79efd2 100644 --- a/integrations/oci/sdk/processor/src/test/resources/io/helidon/integrations/oci/sdk/processor/builder-name-exceptions.txt +++ b/integrations/oci/sdk/codegen/src/test/resources/META-INF/helidon/oci/sdk/codegen/builder-name-exceptions.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. +# Copyright (c) 2023, 2024 Oracle and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,4 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # + test2 diff --git a/integrations/oci/sdk/processor/src/test/resources/io/helidon/integrations/oci/sdk/processor/codegen-exclusions.txt b/integrations/oci/sdk/codegen/src/test/resources/META-INF/helidon/oci/sdk/codegen/codegen-exclusions.txt similarity index 90% rename from integrations/oci/sdk/processor/src/test/resources/io/helidon/integrations/oci/sdk/processor/codegen-exclusions.txt rename to integrations/oci/sdk/codegen/src/test/resources/META-INF/helidon/oci/sdk/codegen/codegen-exclusions.txt index 868b3a34b6a..212142eaea6 100644 --- a/integrations/oci/sdk/processor/src/test/resources/io/helidon/integrations/oci/sdk/processor/codegen-exclusions.txt +++ b/integrations/oci/sdk/codegen/src/test/resources/META-INF/helidon/oci/sdk/codegen/codegen-exclusions.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Oracle and/or its affiliates. +# Copyright (c) 2023, 2024 Oracle and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,4 +13,5 @@ # See the License for the specific language governing permissions and # limitations under the License. # + test1 diff --git a/integrations/oci/sdk/codegen/src/test/resources/expected/Objectstorage__Oci_Client._java_ b/integrations/oci/sdk/codegen/src/test/resources/expected/Objectstorage__Oci_Client._java_ new file mode 100644 index 00000000000..a35ea5ffd90 --- /dev/null +++ b/integrations/oci/sdk/codegen/src/test/resources/expected/Objectstorage__Oci_Client._java_ @@ -0,0 +1,51 @@ +/* + * Copyright (c) {{YEAR}} Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.integrations.generated.com.oracle.bmc.objectstorage; + +import java.util.Optional; + +import io.helidon.common.Generated; +import io.helidon.common.Weight; +import io.helidon.service.registry.Lookup; +import io.helidon.service.registry.Service; + +import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; +import com.oracle.bmc.objectstorage.ObjectStorage; +import com.oracle.bmc.objectstorage.ObjectStorageClient; + +@Generated(value = "io.helidon.integrations.oci.sdk.codegen.OciInjectionCodegenObserver", trigger = "com.oracle.bmc.objectstorage.ObjectStorage") +@Service.Singleton +@Weight(99.0D) +@Service.ExternalContracts(ObjectStorage.class) +class ObjectStorage__Oci_Client implements Service.InjectionPointFactory { + + private final Service.InjectionPointFactory authProvider; + private final Service.InjectionPointFactory builderProvider; + + @Service.Inject + @Deprecated + ObjectStorage__Oci_Client(Service.InjectionPointFactory authProvider, Service.InjectionPointFactory builderProvider) { + this.authProvider = authProvider; + this.builderProvider = builderProvider; + } + + @Override + public Optional> first(Lookup query) { + return Optional.of(Service.QualifiedInstance.create(builderProvider.first(query).orElseThrow().get().build(authProvider.first(query).orElseThrow().get()))); + } + +} diff --git a/integrations/oci/sdk/codegen/src/test/resources/expected/Objectstorage__Oci_ClientBuilder._java_ b/integrations/oci/sdk/codegen/src/test/resources/expected/Objectstorage__Oci_ClientBuilder._java_ new file mode 100644 index 00000000000..5d4b56e0e04 --- /dev/null +++ b/integrations/oci/sdk/codegen/src/test/resources/expected/Objectstorage__Oci_ClientBuilder._java_ @@ -0,0 +1,49 @@ +/* + * Copyright (c) {{YEAR}} Oracle and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.helidon.integrations.generated.com.oracle.bmc.objectstorage; + +import java.util.Optional; + +import io.helidon.common.Generated; +import io.helidon.common.Weight; +import io.helidon.service.registry.Lookup; +import io.helidon.service.registry.Service; + +import com.oracle.bmc.Region; +import com.oracle.bmc.objectstorage.ObjectStorageClient; + +@Generated(value = "io.helidon.integrations.oci.sdk.codegen.OciInjectionCodegenObserver", trigger = "com.oracle.bmc.objectstorage.ObjectStorage") +@Service.Singleton +@Weight(99.0D) +class ObjectStorage__Oci_ClientBuilder implements Service.InjectionPointFactory { + + private final Service.InjectionPointFactory regionProvider; + + @Service.Inject + @Deprecated + ObjectStorage__Oci_ClientBuilder(Service.InjectionPointFactory regionProvider) { + this.regionProvider = regionProvider; + } + + @Override + public Optional> first(Lookup query) { + var builder = ObjectStorageClient.builder(); + regionProvider.first(query).map(Service.QualifiedInstance::get).ifPresent(builder::region); + return Optional.of(Service.QualifiedInstance.create(builder)); + } + +} diff --git a/integrations/oci/sdk/pom.xml b/integrations/oci/sdk/pom.xml index dfdc33625cc..d1c3eae5a38 100644 --- a/integrations/oci/sdk/pom.xml +++ b/integrations/oci/sdk/pom.xml @@ -33,7 +33,7 @@ cdi - processor + codegen runtime diff --git a/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/OciInjectionProcessorObserver.java b/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/OciInjectionProcessorObserver.java deleted file mode 100644 index fa55f2fd3c7..00000000000 --- a/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/OciInjectionProcessorObserver.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.integrations.oci.sdk.processor; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UncheckedIOException; -import java.io.Writer; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.FilerException; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; -import javax.tools.JavaFileObject; - -import io.helidon.common.LazyValue; -import io.helidon.common.types.TypeName; -import io.helidon.common.types.TypeValues; -import io.helidon.common.types.TypedElementInfo; -import io.helidon.inject.api.Activator; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.processor.InjectionAnnotationProcessor; -import io.helidon.inject.processor.ProcessingEvent; -import io.helidon.inject.processor.spi.InjectionAnnotationProcessorObserver; -import io.helidon.inject.tools.TemplateHelper; -import io.helidon.inject.tools.ToolsException; -import io.helidon.inject.tools.TypeNames; - -import static io.helidon.inject.processor.GeneralProcessorUtils.isProviderType; -import static java.util.function.Predicate.not; - -/** - * This processor is an implementation of {@link InjectionAnnotationProcessorObserver}. When on the APT classpath, it will monitor - * {@link InjectionAnnotationProcessor} for all injection points that are - * using the {@code OCI SDK Services} and translate those injection points into code-generated - * {@link Activator}s, {@link ModuleComponent}, etc. for those services / components. - * This process will therefore make the {@code OCI SDK} set of services injectable by your (non-MP-based) Helidon application, and - * be tailored to exactly what is actually used by your application from the SDK. - *

- * For example, if your code had this: - *

- * {@code
- *   @Inject
- *   com.oracle.bmc.ObjectStorage objStore;
- * }
- * 
- * This would result in code generating the necessary artifacts at compile time that will make {@code ObjectStorage} injectable. - *

- * All injection points using the same package name as the OCI SDK (e.g., {@code com.oracle.bmc} as shown with ObjectStorage in - * the case above) will be observed and processed and eventually result in code generation into your - * {@code target/generated-sources} directory. This is the case for any artifact that is attempted to be injected unless there is - * found a configuration signaling an exception to avoid the code generation for the activator. - *

- * The processor will allows exceptions in one of three ways: - *

    - *
  • via the code directly here - see the {@link #shouldProcess} method.
  • - *
  • via resources on the classpath - the implementation looks for files named {@link #TAG_TYPENAME_EXCEPTIONS} in the same - * package name as this class, and will read those resources during initialization. Each line of this file would be a fully - * qualified type name to avoid processing that type name.
  • - *
  • via {@code -A} directives on the compiler command line. Using the same tag as referenced above. The line can be - * comma-delimited, and each token will be treated as a fully qualified type name to signal that the type should be - * not be processed.
  • - *
- * - * @deprecated replaced with {@code helidon-integrations-oci} module - */ -@Deprecated(forRemoval = true, since = "4.1.0") -public class OciInjectionProcessorObserver implements InjectionAnnotationProcessorObserver { - static final String OCI_ROOT_PACKAGE_NAME_PREFIX = "com.oracle.bmc."; - - // all generated sources will have this package prefix - static final String GENERATED_PREFIX = "io.helidon.integrations.generated."; - - // all generated sources will have this class name suffix - static final String GENERATED_CLIENT_SUFFIX = "$$Oci$$Client"; - static final String GENERATED_CLIENT_BUILDER_SUFFIX = GENERATED_CLIENT_SUFFIX + "Builder"; - static final String GENERATED_OCI_ROOT_PACKAGE_NAME_PREFIX = GENERATED_PREFIX + OCI_ROOT_PACKAGE_NAME_PREFIX; - - static final String TAG_TEMPLATE_SERVICE_CLIENT_PROVIDER_NAME = "service-client-provider.hbs"; - static final String TAG_TEMPLATE_SERVICE_CLIENT_BUILDER_PROVIDER_NAME = "service-client-builder-provider.hbs"; - - // note that these can be used as -A values also - static final String TAG_TYPENAME_EXCEPTIONS = "codegen-exclusions"; - static final String TAG_NO_DOT_EXCEPTIONS = "builder-name-exceptions"; - - static final LazyValue> TYPENAME_EXCEPTIONS = LazyValue - .create(OciInjectionProcessorObserver::loadTypeNameExceptions); - static final LazyValue> NO_DOT_EXCEPTIONS = LazyValue - .create(OciInjectionProcessorObserver::loadNoDotExceptions); - - private static final TypeName PROCESSOR_TYPE = TypeName.create(OciInjectionProcessorObserver.class); - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public OciInjectionProcessorObserver() { - } - - @Override - public void onProcessingEvent(ProcessingEvent event) { - ProcessingEnvironment processingEnv = event.processingEnvironment().orElseThrow(); - layerInManualOptions(processingEnv); - event.elementsOfInterest().stream() - .filter(it -> shouldProcess(it, processingEnv)) - .forEach(it -> process(it, processingEnv)); - } - - private void process(TypedElementInfo element, - ProcessingEnvironment processingEnv) { - if (TypeValues.KIND_FIELD.equalsIgnoreCase(element.elementTypeKind())) { - process(element.typeName(), processingEnv); - } else if (TypeValues.KIND_METHOD.equalsIgnoreCase(element.elementTypeKind()) - || TypeValues.KIND_CONSTRUCTOR.equalsIgnoreCase(element.elementTypeKind())) { - element.parameterArguments().stream() - .filter(it -> shouldProcess(it.typeName(), processingEnv)) - .forEach(it -> process(it.typeName(), processingEnv)); - } - } - - private void process(TypeName ociServiceTypeName, - ProcessingEnvironment processingEnv) { - if (isProviderType(ociServiceTypeName) - || ociServiceTypeName.isOptional()) { - ociServiceTypeName = ociServiceTypeName.typeArguments().get(0); - } - assert (!ociServiceTypeName.generic()) : ociServiceTypeName.name(); - assert (ociServiceTypeName.name().startsWith(OCI_ROOT_PACKAGE_NAME_PREFIX)) : ociServiceTypeName.name(); - - TypeName generatedOciServiceClientTypeName = toGeneratedServiceClientTypeName(ociServiceTypeName); - String serviceClientBody = toBody(TAG_TEMPLATE_SERVICE_CLIENT_PROVIDER_NAME, - ociServiceTypeName, - generatedOciServiceClientTypeName); - codegen(generatedOciServiceClientTypeName, serviceClientBody, processingEnv); - - TypeName generatedOciServiceClientBuilderTypeName = toGeneratedServiceClientBuilderTypeName(ociServiceTypeName); - String serviceClientBuilderBody = toBody(TAG_TEMPLATE_SERVICE_CLIENT_BUILDER_PROVIDER_NAME, - ociServiceTypeName, - generatedOciServiceClientTypeName); - codegen(generatedOciServiceClientBuilderTypeName, serviceClientBuilderBody, processingEnv); - } - - private void codegen(TypeName typeName, - String body, - ProcessingEnvironment processingEnv) { - Filer filer = processingEnv.getFiler(); - try { - JavaFileObject javaSrc = filer.createSourceFile(typeName.name()); - try (Writer os = javaSrc.openWriter()) { - os.write(body); - } - } catch (FilerException x) { - processingEnv.getMessager().printWarning("Failed to write java file: " + x); - } catch (Exception x) { - System.getLogger(getClass().getName()).log(System.Logger.Level.ERROR, "Failed to write java file: " + x, x); - processingEnv.getMessager().printError("Failed to write java file: " + x); - } - } - - static TypeName toGeneratedServiceClientTypeName(TypeName typeName) { - return TypeName.builder() - .packageName(GENERATED_PREFIX + typeName.packageName()) - .className(typeName.className() + GENERATED_CLIENT_SUFFIX) - .build(); - } - - static TypeName toGeneratedServiceClientBuilderTypeName(TypeName typeName) { - return TypeName.builder() - .packageName(GENERATED_PREFIX + typeName.packageName()) - .className(typeName.className() + GENERATED_CLIENT_BUILDER_SUFFIX) - .build(); - } - - static String toBody(String templateName, - TypeName ociServiceTypeName, - TypeName generatedOciActivatorTypeName) { - TemplateHelper templateHelper = TemplateHelper.create(); - String template = loadTemplate(templateName); - Map subst = new HashMap<>(); - subst.put("classname", ociServiceTypeName.resolvedName()); - subst.put("simpleclassname", ociServiceTypeName.className()); - subst.put("packagename", generatedOciActivatorTypeName.packageName()); - subst.put("generatedanno", templateHelper.generatedStickerFor(PROCESSOR_TYPE, - ociServiceTypeName, - generatedOciActivatorTypeName)); - subst.put("dot", maybeDot(ociServiceTypeName)); - subst.put("usesRegion", usesRegion(ociServiceTypeName)); - return templateHelper.applySubstitutions(template, subst, true).trim(); - } - - static String maybeDot(TypeName ociServiceTypeName) { - return NO_DOT_EXCEPTIONS.get().contains(ociServiceTypeName.name()) ? "" : "."; - } - - static boolean usesRegion(TypeName ociServiceTypeName) { - // it turns out that the same exceptions used for dotting the builder also applies to whether it uses region - return !NO_DOT_EXCEPTIONS.get().contains(ociServiceTypeName.name()); - } - - static String loadTemplate(String name) { - String path = "io/helidon/integrations/oci/sdk/processor/templates/" + name; - try { - InputStream in = OciInjectionProcessorObserver.class.getClassLoader().getResourceAsStream(path); - if (in == null) { - throw new IOException("Could not find template " + path + " on classpath."); - } - try (in) { - return new String(in.readAllBytes(), StandardCharsets.UTF_8); - } - } catch (Exception e) { - throw new ToolsException(e.getMessage(), e); - } - } - - static Set loadTypeNameExceptions() { - return loadSet(TAG_TYPENAME_EXCEPTIONS); - } - - static Set loadNoDotExceptions() { - return loadSet(TAG_NO_DOT_EXCEPTIONS); - } - - static void layerInManualOptions(ProcessingEnvironment processingEnv) { - Map opts = processingEnv.getOptions(); - TYPENAME_EXCEPTIONS.get().addAll(splitToSet(opts.get(TAG_TYPENAME_EXCEPTIONS))); - NO_DOT_EXCEPTIONS.get().addAll(splitToSet(opts.get(TAG_NO_DOT_EXCEPTIONS))); - } - - static Set splitToSet(String val) { - if (val == null) { - return Set.of(); - } - List list = Arrays.stream(val.split(",")) - .map(String::trim) - .filter(not(String::isEmpty)) - .filter(not(s -> s.startsWith("#"))) - .toList(); - return new LinkedHashSet<>(list); - } - - static Set loadSet(String name) { - // note that we need to keep this mutable for later when we process the env options passed manually in - Set result = new LinkedHashSet<>(); - - name = OciInjectionProcessorObserver.class.getPackageName().replace(".", "/") + "/" + name + ".txt"; - try { - Enumeration resources = OciInjectionProcessorObserver.class.getClassLoader().getResources(name); - while (resources.hasMoreElements()) { - URL url = resources.nextElement(); - try ( - InputStream in = url.openStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) - ) { - reader.lines() - .map(String::trim) - .filter(not(String::isEmpty)) - .filter(not(s -> s.startsWith("#"))) - .forEach(result::add); - } - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - return result; - } - - static boolean shouldProcess(TypedElementInfo element, - ProcessingEnvironment processingEnv) { - if (!element.hasAnnotation(TypeNames.JAKARTA_INJECT_TYPE)) { - return false; - } - - if (TypeValues.KIND_FIELD.equalsIgnoreCase(element.elementTypeKind())) { - return shouldProcess(element.typeName(), processingEnv); - } else if (TypeValues.KIND_METHOD.equalsIgnoreCase(element.elementTypeKind()) - || TypeValues.KIND_CONSTRUCTOR.equalsIgnoreCase(element.elementTypeKind())) { - return element.parameterArguments().stream() - .anyMatch(it -> shouldProcess(it.typeName(), processingEnv)); - } - - return false; - } - - static boolean shouldProcess(TypeName typeName, - ProcessingEnvironment processingEnv) { - if (!typeName.typeArguments().isEmpty() - && isProviderType(typeName) || typeName.isOptional()) { - typeName = typeName.typeArguments().get(0); - } - - String name = typeName.resolvedName(); - if (!name.startsWith(OCI_ROOT_PACKAGE_NAME_PREFIX) - || name.endsWith(".Builder") - || name.endsWith("Client") - || name.endsWith("ClientBuilder") - || TYPENAME_EXCEPTIONS.get().contains(name)) { - return false; - } - - if (processingEnv != null) { - // check to see if we already generated it before, and if so we can skip creating it again - String generatedTypeName = toGeneratedServiceClientTypeName(typeName).name(); - TypeElement typeElement = processingEnv.getElementUtils() - .getTypeElement(generatedTypeName); - return (typeElement == null); - } - - return true; - } - -} diff --git a/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/OciModuleComponentNamer.java b/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/OciModuleComponentNamer.java deleted file mode 100644 index 6042d708796..00000000000 --- a/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/OciModuleComponentNamer.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.integrations.oci.sdk.processor; - -import java.util.Collection; -import java.util.Optional; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.api.ModuleComponent; -import io.helidon.inject.tools.spi.ModuleComponentNamer; - -import static java.util.function.Predicate.not; - -/** - * Avoids using any OCI SDK package name(s) as the {@link ModuleComponent} name that is code-generated. - * - * @deprecated replaced with {@code helidon-integrations-oci} module - */ -@Deprecated(forRemoval = true, since = "4.1.0") -public class OciModuleComponentNamer implements ModuleComponentNamer { - - /** - * Service loader based constructor. - * - * @deprecated this is a Java ServiceLoader implementation and the constructor should not be used directly - */ - @Deprecated - public OciModuleComponentNamer() { - } - - @Override - public Optional suggestedPackageName(Collection typeNames) { - String suggested = typeNames.stream() - .sorted() - .filter(not(it -> it.name().startsWith(OciInjectionProcessorObserver.GENERATED_OCI_ROOT_PACKAGE_NAME_PREFIX))) - .filter(not(it -> it.name().startsWith(OciInjectionProcessorObserver.OCI_ROOT_PACKAGE_NAME_PREFIX))) - .map(TypeName::packageName) - .findFirst().orElse(null); - return Optional.ofNullable(suggested); - } - -} diff --git a/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/package-info.java b/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/package-info.java deleted file mode 100644 index 69f918b1b5c..00000000000 --- a/integrations/oci/sdk/processor/src/main/java/io/helidon/integrations/oci/sdk/processor/package-info.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon Injection Processor Integration for the OCI SDK. - */ -package io.helidon.integrations.oci.sdk.processor; diff --git a/integrations/oci/sdk/processor/src/main/java/module-info.java b/integrations/oci/sdk/processor/src/main/java/module-info.java deleted file mode 100644 index 4e44621fb81..00000000000 --- a/integrations/oci/sdk/processor/src/main/java/module-info.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Helidon Injection Integrations for OCI SDK. - * - * @deprecated replaced with {@code helidon-integrations-oci} module - */ -@Deprecated(forRemoval = true, since = "4.1.0") -module io.helidon.integrations.oci.sdk.processor { - - requires handlebars; - requires java.compiler; - - requires static jakarta.inject; - requires static jdk.jfr; - - requires transitive io.helidon.common.types; - requires transitive io.helidon.inject.processor; - - exports io.helidon.integrations.oci.sdk.processor; - - uses io.helidon.inject.processor.spi.InjectionAnnotationProcessorObserver; - uses io.helidon.inject.tools.spi.ModuleComponentNamer; - - provides io.helidon.inject.processor.spi.InjectionAnnotationProcessorObserver with - io.helidon.integrations.oci.sdk.processor.OciInjectionProcessorObserver; - provides io.helidon.inject.tools.spi.ModuleComponentNamer with - io.helidon.integrations.oci.sdk.processor.OciModuleComponentNamer; - -} diff --git a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/templates/service-client-builder-provider.hbs b/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/templates/service-client-builder-provider.hbs deleted file mode 100644 index 03c73220869..00000000000 --- a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/templates/service-client-builder-provider.hbs +++ /dev/null @@ -1,60 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packagename}}; - -import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; - -import {{classname}}Client; -import {{classname}}Client{{dot}}Builder;{{#if usesRegion}} -import com.oracle.bmc.Region;{{/if}} - -import io.helidon.common.Weight; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.ServiceInfoBasics; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; -import java.util.Optional; - -{{{generatedanno}}} -@Singleton -@Weight(ServiceInfoBasics.DEFAULT_INJECT_WEIGHT) -class {{simpleclassname}}$$Oci$$ClientBuilder implements InjectionPointProvider<{{simpleclassname}}Client{{dot}}Builder> { -{{#if usesRegion}} private final InjectionPointProvider regionProvider; - - @Deprecated - @Inject - {{simpleclassname}}$$Oci$$ClientBuilder(Provider regionProvider) { - this.regionProvider = (InjectionPointProvider) regionProvider; - } -{{else}} - @Deprecated - @Inject - {{simpleclassname}}$$Oci$$ClientBuilder() { - } -{{/if}} - @Override - public Optional<{{simpleclassname}}Client{{dot}}Builder> first(ContextualServiceQuery query) { - {{simpleclassname}}Client{{dot}}Builder builder = {{simpleclassname}}Client.builder();{{#if usesRegion}} - regionProvider.first(query).ifPresent(it -> builder.region(it));{{/if}} - return Optional.of(builder); - } - -} diff --git a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/templates/service-client-provider.hbs b/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/templates/service-client-provider.hbs deleted file mode 100644 index e9731bf155a..00000000000 --- a/integrations/oci/sdk/processor/src/main/resources/io/helidon/integrations/oci/sdk/processor/templates/service-client-provider.hbs +++ /dev/null @@ -1,56 +0,0 @@ -{{! -Copyright (c) 2023 Oracle and/or its affiliates. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -}}{{#header}}{{.}} -{{/header}} -package {{packagename}}; - -import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; - -import {{classname}}Client; -import {{classname}}Client{{dot}}Builder; - -import io.helidon.common.Weight; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.ExternalContracts; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.ServiceInfoBasics; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; -import java.util.Optional; - -{{{generatedanno}}} -@Singleton -@Weight(ServiceInfoBasics.DEFAULT_INJECT_WEIGHT) -@ExternalContracts({{classname}}.class) -class {{simpleclassname}}$$Oci$$Client implements InjectionPointProvider<{{simpleclassname}}Client> { - private final InjectionPointProvider authProvider; - private final InjectionPointProvider<{{simpleclassname}}Client{{dot}}Builder> builderProvider; - - @Deprecated - @Inject - {{simpleclassname}}$$Oci$$Client(Provider authProvider, Provider<{{simpleclassname}}Client{{dot}}Builder> builderProvider) { - this.authProvider = (InjectionPointProvider) authProvider; - this.builderProvider = (InjectionPointProvider<{{simpleclassname}}Client{{dot}}Builder>) builderProvider; - } - - @Override - public Optional<{{simpleclassname}}Client> first(ContextualServiceQuery query) { - return Optional.of(builderProvider.first(query).orElseThrow().build(authProvider.first(query).orElseThrow())); - } - -} diff --git a/integrations/oci/sdk/processor/src/test/java/io/helidon/integrations/oci/sdk/processor/OciInjectionProcessorObserverTest.java b/integrations/oci/sdk/processor/src/test/java/io/helidon/integrations/oci/sdk/processor/OciInjectionProcessorObserverTest.java deleted file mode 100644 index a3cb853d42b..00000000000 --- a/integrations/oci/sdk/processor/src/test/java/io/helidon/integrations/oci/sdk/processor/OciInjectionProcessorObserverTest.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.integrations.oci.sdk.processor; - -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Set; - -import io.helidon.common.types.TypeName; -import io.helidon.inject.tools.ToolsException; - -import com.oracle.bmc.objectstorage.ObjectStorage; -import com.oracle.bmc.streaming.Stream; -import com.oracle.bmc.streaming.StreamAdmin; -import com.oracle.bmc.streaming.StreamAsync; -import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.Test; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; - -class OciInjectionProcessorObserverTest { - - @Test - void generatedInjectionArtifactsForTypicalOciServices() { - TypeName ociServiceType = TypeName.create(ObjectStorage.class); - - TypeName generatedOciServiceClientTypeName = OciInjectionProcessorObserver.toGeneratedServiceClientTypeName(ociServiceType); - assertThat(generatedOciServiceClientTypeName.name(), - equalTo("io.helidon.integrations.generated." + ociServiceType.name() + "$$Oci$$Client")); - - String serviceClientBody = OciInjectionProcessorObserver.toBody(OciInjectionProcessorObserver.TAG_TEMPLATE_SERVICE_CLIENT_PROVIDER_NAME, - ociServiceType, - generatedOciServiceClientTypeName); - assertThat(serviceClientBody, - equalTo(loadStringFromResource("expected/objectstorage$$Oci$$Client._java_"))); - - TypeName generatedOciServiceClientBuilderTypeName = OciInjectionProcessorObserver.toGeneratedServiceClientBuilderTypeName(ociServiceType); - assertThat(generatedOciServiceClientBuilderTypeName.name(), - equalTo("io.helidon.integrations.generated." + ociServiceType.name() + "$$Oci$$ClientBuilder")); - - String serviceClientBuilderBody = OciInjectionProcessorObserver.toBody(OciInjectionProcessorObserver.TAG_TEMPLATE_SERVICE_CLIENT_BUILDER_PROVIDER_NAME, - ociServiceType, - generatedOciServiceClientTypeName); - assertThat(serviceClientBuilderBody, - equalTo(loadStringFromResource("expected/objectstorage$$Oci$$ClientBuilder._java_"))); - } - - @Test - void oddballServiceTypeNames() { - TypeName ociServiceType = TypeName.create(Stream.class); - MatcherAssert.assertThat(OciInjectionProcessorObserver.maybeDot(ociServiceType), - equalTo("")); - MatcherAssert.assertThat(OciInjectionProcessorObserver.usesRegion(ociServiceType), - equalTo(false)); - - ociServiceType = TypeName.create(StreamAsync.class); - MatcherAssert.assertThat(OciInjectionProcessorObserver.maybeDot(ociServiceType), - equalTo("")); - MatcherAssert.assertThat(OciInjectionProcessorObserver.usesRegion(ociServiceType), - equalTo(false)); - - ociServiceType = TypeName.create(StreamAdmin.class); - MatcherAssert.assertThat(OciInjectionProcessorObserver.maybeDot(ociServiceType), - equalTo(".")); - MatcherAssert.assertThat(OciInjectionProcessorObserver.usesRegion(ociServiceType), - equalTo(true)); - } - - @Test - void testShouldProcess() { - TypeName typeName = TypeName.create(ObjectStorage.class); - MatcherAssert.assertThat(OciInjectionProcessorObserver.shouldProcess(typeName, null), - is(true)); - - typeName = TypeName.create("com.oracle.bmc.circuitbreaker.OciCircuitBreaker"); - MatcherAssert.assertThat(OciInjectionProcessorObserver.shouldProcess(typeName, null), - is(false)); - - typeName = TypeName.create("com.oracle.another.Service"); - MatcherAssert.assertThat(OciInjectionProcessorObserver.shouldProcess(typeName, null), - is(false)); - - typeName = TypeName.create("com.oracle.bmc.Service"); - MatcherAssert.assertThat(OciInjectionProcessorObserver.shouldProcess(typeName, null), - is(true)); - - typeName = TypeName.create("com.oracle.bmc.ServiceClient"); - MatcherAssert.assertThat(OciInjectionProcessorObserver.shouldProcess(typeName, null), - is(false)); - - typeName = TypeName.create("com.oracle.bmc.ServiceClientBuilder"); - MatcherAssert.assertThat(OciInjectionProcessorObserver.shouldProcess(typeName, null), - is(false)); - } - - @Test - void loadTypeNameExceptions() { - Set set = OciInjectionProcessorObserver.TYPENAME_EXCEPTIONS.get(); - set.addAll(OciInjectionProcessorObserver.splitToSet(" M1, M2,,, ")); - assertThat(set, - containsInAnyOrder("M1", - "M2", - "test1", - "com.oracle.bmc.Region", - "com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider", - "com.oracle.bmc.circuitbreaker.OciCircuitBreaker" - )); - } - - @Test - void loadNoDotExceptions() { - Set set = OciInjectionProcessorObserver.NO_DOT_EXCEPTIONS.get(); - set.addAll(OciInjectionProcessorObserver.splitToSet("Manual1, Manual2 ")); - assertThat(set, - containsInAnyOrder("Manual1", - "Manual2", - "test2", - "com.oracle.bmc.streaming.Stream", - "com.oracle.bmc.streaming.StreamAsync" - )); - } - - static String loadStringFromResource(String resourceNamePath) { - try { - try (InputStream in = OciInjectionProcessorObserverTest.class.getClassLoader().getResourceAsStream(resourceNamePath)) { - return new String(in.readAllBytes(), StandardCharsets.UTF_8).trim(); - } - } catch (Exception e) { - throw new ToolsException("Failed to load: " + resourceNamePath, e); - } - } - -} diff --git a/integrations/oci/sdk/processor/src/test/java/io/helidon/integrations/oci/sdk/processor/OciModuleComponentNamerTest.java b/integrations/oci/sdk/processor/src/test/java/io/helidon/integrations/oci/sdk/processor/OciModuleComponentNamerTest.java deleted file mode 100644 index c6a6fc227dc..00000000000 --- a/integrations/oci/sdk/processor/src/test/java/io/helidon/integrations/oci/sdk/processor/OciModuleComponentNamerTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.helidon.integrations.oci.sdk.processor; - -import java.util.Set; - -import io.helidon.common.types.TypeName; - -import org.junit.jupiter.api.Test; - -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalEmpty; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; - -class OciModuleComponentNamerTest { - - @Test - void suggestedPackageName() { - OciModuleComponentNamer namer = new OciModuleComponentNamer(); - assertThat(namer.suggestedPackageName(Set.of()), - optionalEmpty()); - assertThat(namer.suggestedPackageName(Set.of(TypeName.create("com.oracle.bmc.whatever.Service"))), - optionalEmpty()); - assertThat(namer.suggestedPackageName(Set.of(TypeName.create("com.oracle.another.whatever.Service"))), - optionalValue(equalTo("com.oracle.another.whatever"))); - assertThat(namer.suggestedPackageName(Set.of(TypeName.create("com.oracle.bmc.Service"), - TypeName.create("com.oracle.another.whatever.Service"))), - optionalValue(equalTo("com.oracle.another.whatever"))); - } - -} diff --git a/integrations/oci/sdk/processor/src/test/resources/expected/objectstorage$$Oci$$Client._java_ b/integrations/oci/sdk/processor/src/test/resources/expected/objectstorage$$Oci$$Client._java_ deleted file mode 100644 index 0fe2c307a02..00000000000 --- a/integrations/oci/sdk/processor/src/test/resources/expected/objectstorage$$Oci$$Client._java_ +++ /dev/null @@ -1,40 +0,0 @@ -package io.helidon.integrations.generated.com.oracle.bmc.objectstorage; - -import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; - -import com.oracle.bmc.objectstorage.ObjectStorageClient; -import com.oracle.bmc.objectstorage.ObjectStorageClient.Builder; - -import io.helidon.common.Weight; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.ExternalContracts; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.ServiceInfoBasics; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; -import java.util.Optional; - -@io.helidon.common.Generated(value = "io.helidon.integrations.oci.sdk.processor.OciInjectionProcessorObserver", trigger = "com.oracle.bmc.objectstorage.ObjectStorage") -@Singleton -@Weight(ServiceInfoBasics.DEFAULT_INJECT_WEIGHT) -@ExternalContracts(com.oracle.bmc.objectstorage.ObjectStorage.class) -class ObjectStorage$$Oci$$Client implements InjectionPointProvider { - private final InjectionPointProvider authProvider; - private final InjectionPointProvider builderProvider; - - @Deprecated - @Inject - ObjectStorage$$Oci$$Client(Provider authProvider, Provider builderProvider) { - this.authProvider = (InjectionPointProvider) authProvider; - this.builderProvider = (InjectionPointProvider) builderProvider; - } - - @Override - public Optional first(ContextualServiceQuery query) { - return Optional.of(builderProvider.first(query).orElseThrow().build(authProvider.first(query).orElseThrow())); - } - -} diff --git a/integrations/oci/sdk/processor/src/test/resources/expected/objectstorage$$Oci$$ClientBuilder._java_ b/integrations/oci/sdk/processor/src/test/resources/expected/objectstorage$$Oci$$ClientBuilder._java_ deleted file mode 100644 index 7111873562a..00000000000 --- a/integrations/oci/sdk/processor/src/test/resources/expected/objectstorage$$Oci$$ClientBuilder._java_ +++ /dev/null @@ -1,39 +0,0 @@ -package io.helidon.integrations.generated.com.oracle.bmc.objectstorage; - -import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; - -import com.oracle.bmc.objectstorage.ObjectStorageClient; -import com.oracle.bmc.objectstorage.ObjectStorageClient.Builder; -import com.oracle.bmc.Region; - -import io.helidon.common.Weight; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.ServiceInfoBasics; - -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; -import java.util.Optional; - -@io.helidon.common.Generated(value = "io.helidon.integrations.oci.sdk.processor.OciInjectionProcessorObserver", trigger = "com.oracle.bmc.objectstorage.ObjectStorage") -@Singleton -@Weight(ServiceInfoBasics.DEFAULT_INJECT_WEIGHT) -class ObjectStorage$$Oci$$ClientBuilder implements InjectionPointProvider { - private final InjectionPointProvider regionProvider; - - @Deprecated - @Inject - ObjectStorage$$Oci$$ClientBuilder(Provider regionProvider) { - this.regionProvider = (InjectionPointProvider) regionProvider; - } - - @Override - public Optional first(ContextualServiceQuery query) { - ObjectStorageClient.Builder builder = ObjectStorageClient.builder(); - regionProvider.first(query).ifPresent(it -> builder.region(it)); - return Optional.of(builder); - } - -} diff --git a/integrations/oci/sdk/runtime/pom.xml b/integrations/oci/sdk/runtime/pom.xml index d7e3cf4a3a3..027eb78d755 100644 --- a/integrations/oci/sdk/runtime/pom.xml +++ b/integrations/oci/sdk/runtime/pom.xml @@ -24,13 +24,14 @@ io.helidon.integrations.oci.sdk helidon-integrations-oci-sdk-project 4.2.0-SNAPSHOT + ../pom.xml 4.0.0 helidon-integrations-oci-sdk-runtime Helidon Integrations OCI Injection Runtime - Helidon Injection Framework Runtime support for the OCI SDK + Helidon Service Registry Runtime support for the OCI SDK etc/spotbugs/exclude.xml @@ -55,33 +56,14 @@ helidon-config-yaml - io.helidon.inject.configdriven - helidon-inject-configdriven-api - - - io.helidon.config - helidon-config-metadata - true - - - io.helidon.inject - helidon-inject-runtime - - - jakarta.inject - jakarta.inject-api - provided + io.helidon.service + helidon-service-registry io.helidon.common.testing helidon-common-testing-junit5 test - - io.helidon.inject - helidon-inject-testing - test - org.hamcrest hamcrest-all @@ -108,46 +90,56 @@ true - io.helidon.inject.configdriven - helidon-inject-configdriven-processor + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.config.metadata + helidon-config-metadata-codegen ${helidon.version} io.helidon.builder - helidon-builder-processor + helidon-builder-codegen ${helidon.version} - io.helidon.common.processor - helidon-common-processor-helidon-copyright + io.helidon.service + helidon-service-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-helidon-copyright ${helidon.version} - io.helidon.builder - helidon-builder-processor + io.helidon.codegen + helidon-codegen-apt ${helidon.version} - io.helidon.inject.configdriven - helidon-inject-configdriven-processor + io.helidon.config.metadata + helidon-config-metadata-codegen + ${helidon.version} + + + io.helidon.builder + helidon-builder-codegen ${helidon.version} - io.helidon.common.processor - helidon-common-processor-helidon-copyright + io.helidon.service + helidon-service-codegen ${helidon.version} - io.helidon.config - helidon-config-metadata-processor + io.helidon.codegen + helidon-codegen-helidon-copyright ${helidon.version} diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java index d2b5a8d400f..c1fc7dfdfa1 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,12 +27,10 @@ import java.util.Optional; import java.util.function.Supplier; -import io.helidon.common.Weight; import io.helidon.common.types.Annotation; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.ServiceInfoBasics; +import io.helidon.service.registry.Dependency; +import io.helidon.service.registry.Lookup; +import io.helidon.service.registry.Service; import com.oracle.bmc.ConfigFileReader; import com.oracle.bmc.Region; @@ -43,8 +41,6 @@ import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider; import com.oracle.bmc.auth.SimplePrivateKeySupplier; import com.oracle.bmc.auth.StringPrivateKeySupplier; -import jakarta.inject.Named; -import jakarta.inject.Singleton; import static io.helidon.common.types.Annotations.findFirst; @@ -55,9 +51,8 @@ * @see OciConfigBlueprint * @see OciConfig */ -@Singleton -@Weight(ServiceInfoBasics.DEFAULT_INJECT_WEIGHT) -class OciAuthenticationDetailsProvider implements InjectionPointProvider { +@Service.Singleton +class OciAuthenticationDetailsProvider implements Service.InjectionPointFactory { static final System.Logger LOGGER = System.getLogger(OciAuthenticationDetailsProvider.class.getName()); static final String KEY_AUTH_STRATEGY = "auth-strategy"; @@ -81,17 +76,19 @@ class OciAuthenticationDetailsProvider implements InjectionPointProvider first(ContextualServiceQuery query) { + public Optional> first(Lookup lookup) { OciConfig ociConfig = OciExtension.ociConfig(); - String requestedNamedProfile = toNamedProfile(query.injectionPointInfo().orElse(null)); + String requestedNamedProfile = toNamedProfile(lookup.dependency().orElse(null)); // if the injection point names a profile for auth strategy then use it if (requestedNamedProfile != null && !requestedNamedProfile.isBlank()) { ociConfig = OciConfig.builder(ociConfig).configProfile(requestedNamedProfile).build(); } - return Optional.of(select(ociConfig, true).authStrategy().select(ociConfig)); + return Optional.of(Service.QualifiedInstance.create(select(ociConfig, true) + .authStrategy() + .select(ociConfig))); } /** @@ -125,8 +122,8 @@ static Supply select(OciConfig ociConfig, + OciConfig.CONFIG_KEY); } - static String toNamedProfile(InjectionPointInfo.Builder ipiBuilder) { - Optional named = findFirst(Named.class, ipiBuilder.qualifiers()); + static String toNamedProfile(Dependency.Builder ipiBuilder) { + Optional named = findFirst(Service.Named.class, ipiBuilder.qualifiers()); if (named.isEmpty()) { return null; } @@ -139,12 +136,12 @@ static String toNamedProfile(InjectionPointInfo.Builder ipiBuilder) { return nameProfile.trim(); } - static String toNamedProfile(InjectionPointInfo ipi) { + static String toNamedProfile(Dependency ipi) { if (ipi == null) { return null; } - Optional named = findFirst(Named.class, ipi.qualifiers()); + Optional named = findFirst(Service.Named.class, ipi.qualifiers()); if (named.isEmpty()) { return null; } diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailability.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailability.java index 3577ce1817f..4b6d5e92ba0 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailability.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailability.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ package io.helidon.integrations.oci.sdk.runtime; -import io.helidon.inject.api.Contract; +import io.helidon.service.registry.Service; /** * Provides a convenient contract for checking whether the current runtime environment is running on/inside an OCI compute node. @@ -24,7 +24,7 @@ * @see OciExtension * @deprecated replaced with {@code helidon-integrations-oci} module */ -@Contract +@Service.Contract @Deprecated(forRemoval = true, since = "4.1.0") public interface OciAvailability { diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailabilityDefault.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailabilityDefault.java index 07f86206022..9c47f24c346 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailabilityDefault.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAvailabilityDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,11 +22,9 @@ import java.net.InetAddress; import java.net.UnknownHostException; -import io.helidon.common.Weight; -import io.helidon.inject.api.ServiceInfoBasics; +import io.helidon.service.registry.Service; import com.oracle.bmc.Region; -import jakarta.inject.Singleton; import static com.oracle.bmc.auth.AbstractFederationClientAuthenticationDetailsProviderBuilder.METADATA_SERVICE_BASE_URL; @@ -34,8 +32,7 @@ * This (overridable) implementation will check the {@link OciConfig} for {@code IMDS} availability. And if it is found to be * available, will also perform a secondary check on {@link Region#getRegionFromImds()} to ensure it returns a non-null value. */ -@Singleton -@Weight(ServiceInfoBasics.DEFAULT_INJECT_WEIGHT) +@Service.Singleton class OciAvailabilityDefault implements OciAvailability { private static final String OPC_PATH = getOpcPath(METADATA_SERVICE_BASE_URL); diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciConfigBlueprint.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciConfigBlueprint.java index 4731a55ce5f..099d9649489 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciConfigBlueprint.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciConfigBlueprint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,9 +25,6 @@ import io.helidon.builder.api.Option; import io.helidon.builder.api.Prototype; -import io.helidon.config.metadata.Configured; -import io.helidon.config.metadata.ConfiguredOption; -import io.helidon.config.metadata.ConfiguredValue; import com.oracle.bmc.ConfigFileReader; @@ -86,7 +83,7 @@ */ // note: this is intended to be a replica to the properties carried from the cdi integrations previously done for MP @Prototype.Blueprint -@Configured(root = true, prefix = OciConfigBlueprint.CONFIG_KEY) +@Prototype.Configured(OciConfigBlueprint.CONFIG_KEY) @Deprecated(forRemoval = true, since = "4.1.0") @Prototype.Annotated("java.lang.Deprecated(forRemoval = true, since = \"4.1.0\")") interface OciConfigBlueprint { @@ -109,12 +106,13 @@ interface OciConfigBlueprint { * * @return the singular authentication strategy to be applied */ - @ConfiguredOption(allowedValues = { - @ConfiguredValue(value = VAL_AUTO, description = "auto select first applicable"), - @ConfiguredValue(value = VAL_CONFIG, description = "simple authentication provider"), - @ConfiguredValue(value = VAL_CONFIG_FILE, description = "config file authentication provider"), - @ConfiguredValue(value = VAL_INSTANCE_PRINCIPALS, description = "instance principals authentication provider"), - @ConfiguredValue(value = VAL_RESOURCE_PRINCIPAL, description = "resource principals authentication provider"), + @Option.Configured + @Option.AllowedValues({ + @Option.AllowedValue(value = VAL_AUTO, description = "auto select first applicable"), + @Option.AllowedValue(value = VAL_CONFIG, description = "simple authentication provider"), + @Option.AllowedValue(value = VAL_CONFIG_FILE, description = "config file authentication provider"), + @Option.AllowedValue(value = VAL_INSTANCE_PRINCIPALS, description = "instance principals authentication provider"), + @Option.AllowedValue(value = VAL_RESOURCE_PRINCIPAL, description = "resource principals authentication provider") }) Optional authStrategy(); @@ -148,12 +146,13 @@ interface OciConfigBlueprint { * @return the list of authentication strategies that will be applied, defaulting to {@code auto} * @see io.helidon.integrations.oci.sdk.runtime.OciAuthenticationDetailsProvider.AuthStrategy */ - @ConfiguredOption(allowedValues = { - @ConfiguredValue(value = VAL_AUTO, description = "auto select first applicable"), - @ConfiguredValue(value = VAL_CONFIG, description = "simple authentication provider"), - @ConfiguredValue(value = VAL_CONFIG_FILE, description = "config file authentication provider"), - @ConfiguredValue(value = VAL_INSTANCE_PRINCIPALS, description = "instance principals authentication provider"), - @ConfiguredValue(value = VAL_RESOURCE_PRINCIPAL, description = "resource principal authentication provider"), + @Option.Configured + @Option.AllowedValues({ + @Option.AllowedValue(value = VAL_AUTO, description = "auto select first applicable"), + @Option.AllowedValue(value = VAL_CONFIG, description = "simple authentication provider"), + @Option.AllowedValue(value = VAL_CONFIG_FILE, description = "config file authentication provider"), + @Option.AllowedValue(value = VAL_INSTANCE_PRINCIPALS, description = "instance principals authentication provider"), + @Option.AllowedValue(value = VAL_RESOURCE_PRINCIPAL, description = "resource principal authentication provider"), }) List authStrategies(); @@ -169,7 +168,7 @@ interface OciConfigBlueprint { * * @return the OCI configuration profile path */ - @ConfiguredOption(key = "config.path") + @Option.Configured("config.path") Optional configPath(); /** @@ -182,7 +181,8 @@ interface OciConfigBlueprint { * * @return the optional OCI configuration/auth profile name */ - @ConfiguredOption(value = DEFAULT_PROFILE_NAME, key = "config.profile") + @Option.Configured("config.profile") + @Option.Default(DEFAULT_PROFILE_NAME) Optional configProfile(); /** @@ -196,7 +196,7 @@ interface OciConfigBlueprint { * * @return the OCI authentication fingerprint */ - @ConfiguredOption(key = "auth.fingerprint") + @Option.Configured("auth.fingerprint") Optional authFingerprint(); /** @@ -211,7 +211,8 @@ interface OciConfigBlueprint { * * @return the OCI authentication key file */ - @ConfiguredOption(value = "oci_api_key.pem", key = "auth.keyFile") + @Option.Configured("auth.keyFile") + @Option.Default("oci_api_key.pem") String authKeyFile(); /** @@ -226,7 +227,7 @@ interface OciConfigBlueprint { * * @return the OCI authentication key file path */ - @ConfiguredOption(key = "auth.private-key-path") + @Option.Configured("auth.private-key-path") Optional authPrivateKeyPath(); /** @@ -242,7 +243,7 @@ interface OciConfigBlueprint { * @return the OCI authentication private key */ // See https://github.com/helidon-io/helidon/issues/6908 - @ConfiguredOption(key = "auth.private-key") + @Option.Configured("auth.private-key") @Option.Confidential Optional authPrivateKey(); @@ -257,7 +258,7 @@ interface OciConfigBlueprint { * @return the OCI authentication passphrase */ // See https://github.com/helidon-io/helidon/issues/6908 - @ConfiguredOption(key = "auth.passphrase") + @Option.Configured("auth.passphrase") @Option.Confidential Optional authPassphrase(); @@ -271,7 +272,7 @@ interface OciConfigBlueprint { * * @return the OCI region */ - @ConfiguredOption(key = "auth.region") + @Option.Configured("auth.region") Optional authRegion(); /** @@ -284,7 +285,7 @@ interface OciConfigBlueprint { * * @return the OCI tenant id */ - @ConfiguredOption(key = "auth.tenant-id") + @Option.Configured("auth.tenant-id") Optional authTenantId(); /** @@ -297,7 +298,7 @@ interface OciConfigBlueprint { * * @return the OCI user id */ - @ConfiguredOption(key = "auth.user-id") + @Option.Configured("auth.user-id") Optional authUserId(); /** @@ -307,7 +308,8 @@ interface OciConfigBlueprint { * * @return the OCI IMDS hostname */ - @ConfiguredOption(value = IMDS_HOSTNAME, key = "imds.hostname") + @Option.Configured("imds.hostname") + @Option.Default(IMDS_HOSTNAME) String imdsHostName(); /** @@ -318,7 +320,8 @@ interface OciConfigBlueprint { * @return the OCI IMDS connection timeout * @see OciAvailability */ - @ConfiguredOption(value = "PT0.1S", key = "imds.timeout.milliseconds") + @Option.Configured("imds.timeout.milliseconds") + @Option.Default("PT0.1S") Duration imdsTimeout(); /** diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciExtension.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciExtension.java index a4823d6fafb..579472b9fdc 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciExtension.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,12 +24,11 @@ import java.util.function.Supplier; import io.helidon.common.LazyValue; +import io.helidon.common.config.GlobalConfig; import io.helidon.config.Config; import io.helidon.config.ConfigSources; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; +import io.helidon.service.registry.ServiceRegistry; +import io.helidon.service.registry.ServiceRegistryManager; import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; @@ -52,7 +51,7 @@ * terminology and general approach before continuing further. *

* This module enables the - * {@linkplain jakarta.inject.Inject injection} of any service + * {@linkplain io.helidon.service.registry.Service.Inject injection} of any service * interface, service client, service client * builder, asynchronous service interface, * asynchronous service client, or asynchronous service @@ -60,7 +59,7 @@ * href="https://docs.oracle.com/en-us/iaas/tools/java/latest/index.html" * target="_top">Oracle Cloud Infrastructure Java SDK. *

- * Additionally, this module enables the {@linkplain jakarta.inject.Inject injection} + * Additionally, this module enables the {@linkplain io.helidon.service.registry.Service.Inject injection} * of the {@link com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider}, * which allows the corresponding service client to authenticate with the service. *

In all cases, user-supplied configuration will be preferred over any @@ -69,8 +68,8 @@ *

Basic Usage

* * To use this extension, make sure it is on your project's runtime - * classpath. Also be sure the helidon-integrations-oci-processor is - * on your APT/compile-time classpath. To {@linkplain jakarta.inject.Inject inject} a service + * classpath. Also be sure the helidon-integrations-oci-codegen is + * on your APT. To {@linkplain io.helidon.service.registry.Service.Inject inject} a service * interface named * com.oracle.bmc.cloudexample.CloudExample * (or an analogous asynchronous service interface), you will also @@ -83,7 +82,7 @@ * *

Advanced Usage

* - *

In the course of providing {@linkplain jakarta.inject.Inject + *

In the course of providing {@linkplain io.helidon.service.registry.Service.Inject * injection support} for a service interface or an asynchronous * service interface, this {@linkplain java.security.cert.Extension extension} will * create service client builder and asynchronous service client @@ -118,8 +117,6 @@ * @see Oracle Cloud Infrastructure Java SDK - * - * @deprecated replaced with {@code helidon-integrations-oci} module */ @Deprecated(forRemoval = true, since = "4.1.0") public final class OciExtension { @@ -134,6 +131,10 @@ public final class OciExtension { .map(AuthStrategy::id) .toList()) .build()); + + // the field is not final (and volatile) so tests can replace the injection services used by this instance + private static volatile LazyValue injectionServices = + LazyValue.create(ServiceRegistryManager::create); private static String overrideOciConfigFile; private static volatile Supplier ociConfigSupplier; private static volatile Supplier fallbackConfigSupplier; @@ -163,7 +164,7 @@ private OciExtension() { * oci-specific bootstrap {@link io.helidon.config.spi.ConfigSource}. *

* If the implementation is unable to find this file, then a fallback mechanism will be used to find it in the configuration - * found in the {@link InjectionServices#globalBootstrap()}, using a top-level attribute key named + * based on {@link io.helidon.common.config.GlobalConfig}, using a top-level attribute key named * {@value OciConfigBlueprint#CONFIG_KEY}. *

* The final fallback mechanism will use an {@code auto} authentication strategy - see {@link OciConfigBlueprint} for details. @@ -180,10 +181,7 @@ public static OciConfig ociConfig() { } // fallback - config = InjectionServices.globalBootstrap() - .flatMap(Bootstrap::config) - .map(it -> it.get(OciConfig.CONFIG_KEY)) - .orElse(null); + config = GlobalConfig.config().get("oci"); if (isSufficientlyConfigured(config)) { return OciConfig.create(config); } @@ -200,10 +198,10 @@ public static OciConfig ociConfig() { */ public static Supplier ociAuthenticationProvider() { return () -> { - Services services = InjectionServices.realizedServices(); - ServiceProvider authProvider = - services.lookupFirst(AbstractAuthenticationDetailsProvider.class); - return Objects.requireNonNull(authProvider.get()); + ServiceRegistry registry = injectionServices.get().registry(); + Supplier authProvider = + registry.supply(AbstractAuthenticationDetailsProvider.class); + return authProvider.get(); }; } @@ -288,4 +286,7 @@ static String ociConfigFilename() { return (overrideOciConfigFile == null) ? DEFAULT_OCI_GLOBAL_CONFIG_FILE : overrideOciConfigFile; } + static void serviceRegistry(ServiceRegistryManager services) { + OciExtension.injectionServices = LazyValue.create(services); + } } diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProvider.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProvider.java index dc03b9b64aa..8dc951f80a7 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProvider.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,45 +18,32 @@ import java.util.Optional; -import io.helidon.common.Weight; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionPointProvider; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.ServiceInfoBasics; +import io.helidon.service.registry.Lookup; +import io.helidon.service.registry.Qualifier; +import io.helidon.service.registry.Service; import com.oracle.bmc.Region; -import jakarta.inject.Singleton; - -import static io.helidon.integrations.oci.sdk.runtime.OciAuthenticationDetailsProvider.toNamedProfile; /** - * Can optionally be used to return a {@link Region} appropriate for the {@link InjectionPointInfo} context. + * Can optionally be used to return a {@link Region} appropriate for the {@link io.helidon.service.registry.Dependency} context. */ -@Singleton -@Weight(ServiceInfoBasics.DEFAULT_INJECT_WEIGHT) -class OciRegionProvider implements InjectionPointProvider { +@Service.Singleton +class OciRegionProvider implements Service.InjectionPointFactory { OciRegionProvider() { } @Override - public Region get() { - return first(ContextualServiceQuery.builder() - .serviceInfoCriteria(InjectionServices.EMPTY_CRITERIA) - .expected(false) - .build()) - .orElseThrow(); - } - - @Override - public Optional first(ContextualServiceQuery query) { - String requestedNamedProfile = toNamedProfile(query.injectionPointInfo().orElse(null)); + public Optional> first(Lookup query) { + String requestedNamedProfile = query.dependency() + .map(OciAuthenticationDetailsProvider::toNamedProfile) + .orElse(null); Region region = toRegionFromNamedProfile(requestedNamedProfile); if (region == null) { region = Region.getRegionFromImds(); } - return Optional.ofNullable(region); + return Optional.ofNullable(region) + .map(it -> Service.QualifiedInstance.create(it, Qualifier.createNamed(it.getRegionId()))); } static Region toRegionFromNamedProfile(String requestedNamedProfile) { diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/package-info.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/package-info.java index 46584e04038..518b58264f4 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/package-info.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,6 @@ */ /** - * Helidon Injection Runtime Integrations to support OCI SDK. + * Helidon Service Registry Integrations to support OCI SDK. */ package io.helidon.integrations.oci.sdk.runtime; diff --git a/integrations/oci/sdk/runtime/src/main/java/module-info.java b/integrations/oci/sdk/runtime/src/main/java/module-info.java index 2ba16341560..debf16fed45 100644 --- a/integrations/oci/sdk/runtime/src/main/java/module-info.java +++ b/integrations/oci/sdk/runtime/src/main/java/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ /** - * Helidon Injection Integrations to support OCI Runtime module. + * Helidon Service Registry Integrations to support OCI Runtime module. * * @deprecated replaced with {@code helidon-integrations-oci} module */ @@ -25,18 +25,9 @@ requires io.helidon.builder.api; requires oci.java.sdk.common; - requires static io.helidon.config.metadata; - requires static jakarta.annotation; - requires static jakarta.inject; - requires transitive io.helidon.common; requires transitive io.helidon.config; - requires transitive io.helidon.inject.runtime; + requires io.helidon.service.registry; exports io.helidon.integrations.oci.sdk.runtime; - - uses io.helidon.inject.api.ModuleComponent; - - provides io.helidon.inject.api.ModuleComponent with - io.helidon.integrations.oci.sdk.runtime.Injection$$Module; } diff --git a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java index 09437451529..35d562c75a9 100644 --- a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java +++ b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,29 +19,28 @@ import java.io.UncheckedIOException; import java.util.Objects; import java.util.Set; +import java.util.function.Supplier; import io.helidon.builder.api.Option; +import io.helidon.common.config.GlobalConfig; import io.helidon.common.types.Annotation; import io.helidon.config.Config; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; +import io.helidon.service.registry.Dependency; +import io.helidon.service.registry.Qualifier; +import io.helidon.service.registry.Service; +import io.helidon.service.registry.ServiceRegistry; +import io.helidon.service.registry.ServiceRegistryConfig; +import io.helidon.service.registry.ServiceRegistryException; +import io.helidon.service.registry.ServiceRegistryManager; import com.oracle.bmc.Region; import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; import com.oracle.bmc.auth.SimpleAuthenticationDetailsProvider; -import jakarta.inject.Named; -import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; @@ -51,8 +50,8 @@ class OciAuthenticationDetailsProviderTest { - InjectionServices injectionServices; - Services services; + static ServiceRegistryManager registryManager; + static ServiceRegistry registry; @BeforeEach @AfterEach @@ -62,43 +61,46 @@ void reset() { @AfterAll static void tearDown() { - resetAll(); + if (registryManager != null) { + registryManager.shutdown(); + } } - void resetWith(Config config) { - resetAll(); - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); + void resetWith(Config config, ServiceRegistryConfig injectionConfig) { + GlobalConfig.config(() -> config, true); + tearDown(); + registryManager = ServiceRegistryManager.create(injectionConfig); + registry = registryManager.registry(); } @Test void testCanReadPath() { - MatcherAssert.assertThat(OciAuthenticationDetailsProvider.canReadPath("./target"), + assertThat(OciAuthenticationDetailsProvider.canReadPath("./target"), is(true)); - MatcherAssert.assertThat(OciAuthenticationDetailsProvider.canReadPath("./~bogus~"), + assertThat(OciAuthenticationDetailsProvider.canReadPath("./~bogus~"), is(false)); } @Test void testUserHomePrivateKeyPath() { OciConfig ociConfig = Objects.requireNonNull(OciExtension.ociConfig()); - MatcherAssert.assertThat(OciAuthenticationDetailsProvider.userHomePrivateKeyPath(ociConfig), + assertThat(OciAuthenticationDetailsProvider.userHomePrivateKeyPath(ociConfig), endsWith("/.oci/oci_api_key.pem")); ociConfig = OciConfig.builder(ociConfig) .configPath("/decoy/path") .authKeyFile("key.pem") .build(); - MatcherAssert.assertThat(OciAuthenticationDetailsProvider.userHomePrivateKeyPath(ociConfig), + assertThat(OciAuthenticationDetailsProvider.userHomePrivateKeyPath(ociConfig), endsWith("/.oci/key.pem")); } @Test void testToNamedProfile() { - assertThat(OciAuthenticationDetailsProvider.toNamedProfile((InjectionPointInfo) null), + assertThat(OciAuthenticationDetailsProvider.toNamedProfile((Dependency) null), nullValue()); - InjectionPointInfo.Builder ipi = InjectionPointInfo.builder() + Dependency.Builder ipi = Dependency.builder() .annotations(Set.of()); assertThat(OciAuthenticationDetailsProvider.toNamedProfile(ipi), nullValue()); @@ -107,17 +109,17 @@ void testToNamedProfile() { assertThat(OciAuthenticationDetailsProvider.toNamedProfile(ipi), nullValue()); - ipi.addAnnotation(Annotation.create(Named.class)); + ipi.addAnnotation(Annotation.create(Service.Named.class)); assertThat(OciAuthenticationDetailsProvider.toNamedProfile(ipi), nullValue()); ipi.qualifiers(Set.of(Qualifier.create(Option.Singular.class), - Qualifier.create(Named.class, ""))); + Qualifier.createNamed(""))); assertThat(OciAuthenticationDetailsProvider.toNamedProfile(ipi), nullValue()); ipi.qualifiers(Set.of(Qualifier.create(Option.Singular.class), - Qualifier.create(Named.class, " profileName "))); + Qualifier.createNamed("profileName"))); assertThat(OciAuthenticationDetailsProvider.toNamedProfile(ipi), equalTo("profileName")); } @@ -161,15 +163,13 @@ void authStrategiesAvailability() { @Test void selectionWhenNoConfigIsSet() { - Config config = OciExtensionTest.createTestConfig( - OciExtensionTest.basicTestingConfigSource()); - resetWith(config); + resetWith(Config.empty(), ServiceRegistryConfig.create()); - assertThat(OciExtension.isSufficientlyConfigured(config), + assertThat(OciExtension.isSufficientlyConfigured(Config.empty()), is(false)); - ServiceProvider authServiceProvider = - services.lookupFirst(AbstractAuthenticationDetailsProvider.class, true).orElseThrow(); + Supplier authServiceProvider = + registry.supply(AbstractAuthenticationDetailsProvider.class); Objects.requireNonNull(authServiceProvider); // this code is dependent upon whether and OCI config-file is present - so leaving this commented out intentionally @@ -182,15 +182,14 @@ void selectionWhenNoConfigIsSet() { @Test void selectionWhenFileConfigIsSetWithAuto() { Config config = OciExtensionTest.createTestConfig( - OciExtensionTest.basicTestingConfigSource(), OciExtensionTest.ociAuthConfigStrategies(OciAuthenticationDetailsProvider.VAL_AUTO), OciExtensionTest.ociAuthConfigFile("./target", "profile")); - resetWith(config); + resetWith(config, ServiceRegistryConfig.create()); - ServiceProvider authServiceProvider = - services.lookupFirst(AbstractAuthenticationDetailsProvider.class, true).orElseThrow(); + Supplier authServiceProvider = + registry.supply(AbstractAuthenticationDetailsProvider.class); - InjectionServiceProviderException e = assertThrows(InjectionServiceProviderException.class, authServiceProvider::get); + ServiceRegistryException e = assertThrows(ServiceRegistryException.class, authServiceProvider::get); assertThat(e.getCause().getClass(), equalTo(UncheckedIOException.class)); } @@ -198,13 +197,12 @@ void selectionWhenFileConfigIsSetWithAuto() { @Test void selectionWhenSimpleConfigIsSetWithAuto() { Config config = OciExtensionTest.createTestConfig( - OciExtensionTest.basicTestingConfigSource(), OciExtensionTest.ociAuthConfigStrategies(OciAuthenticationDetailsProvider.VAL_AUTO), OciExtensionTest.ociAuthSimpleConfig("tenant", "user", "passphrase", "fp", "privKey", null, "us-phoenix-1")); - resetWith(config); + resetWith(config, ServiceRegistryConfig.create()); - ServiceProvider authServiceProvider = - services.lookupFirst(AbstractAuthenticationDetailsProvider.class, true).orElseThrow(); + Supplier authServiceProvider = + registry.supply(AbstractAuthenticationDetailsProvider.class); AbstractAuthenticationDetailsProvider authProvider = authServiceProvider.get(); assertThat(authProvider.getClass(), diff --git a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciExtensionTest.java b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciExtensionTest.java index a0721638351..40444c008c8 100644 --- a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciExtensionTest.java +++ b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciExtensionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,8 @@ import io.helidon.config.Config; import io.helidon.config.ConfigSources; import io.helidon.config.MapConfigSource; -import io.helidon.inject.api.Bootstrap; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.InjectionServices; +import io.helidon.service.registry.ServiceRegistryException; +import io.helidon.service.registry.ServiceRegistryManager; import com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider; import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; @@ -37,7 +36,6 @@ import org.junit.jupiter.api.Test; import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; @@ -52,16 +50,82 @@ * Tests for {@link OciExtension} and {@link OciConfig}. */ class OciExtensionTest { + private ServiceRegistryManager registryManager; + + static Config createTestConfig(MapConfigSource.Builder... builders) { + return Config.builder(builders) + .disableEnvironmentVariablesSource() + .disableSystemPropertiesSource() + .build(); + } + + static MapConfigSource.Builder ociAuthConfigStrategies(String strategy, + String... strategies) { + Map map = new HashMap<>(); + if (strategy != null) { + map.put(OciConfig.CONFIG_KEY + ".auth-strategy", strategy); + } + if (strategies != null && strategies.length != 0) { + map.put(OciConfig.CONFIG_KEY + ".auth-strategies", String.join(",", strategies)); + } + return ConfigSources.create(map, "config-oci-auth-strategies"); + } + + static MapConfigSource.Builder ociAuthConfigFile(String configPath, + String profile) { + Map map = new HashMap<>(); + if (configPath != null) { + map.put(OciConfig.CONFIG_KEY + ".config.path", configPath); + } + if (profile != null) { + map.put(OciConfig.CONFIG_KEY + ".config.profile", String.join(",", profile)); + } + return ConfigSources.create(map, "config-oci-auth-config"); + } + + static MapConfigSource.Builder ociAuthSimpleConfig(String tenantId, + String userId, + String passPhrase, + String fingerPrint, + String privateKey, + String privateKeyPath, + String region) { + Map map = new HashMap<>(); + if (tenantId != null) { + map.put(OciConfig.CONFIG_KEY + ".auth.tenant-id", tenantId); + } + if (userId != null) { + map.put(OciConfig.CONFIG_KEY + ".auth.user-id", userId); + } + if (passPhrase != null) { + map.put(OciConfig.CONFIG_KEY + ".auth.passphrase", passPhrase); + } + if (fingerPrint != null) { + map.put(OciConfig.CONFIG_KEY + ".auth.fingerprint", fingerPrint); + } + if (privateKey != null) { + map.put(OciConfig.CONFIG_KEY + ".auth.private-key", privateKey); + } + if (privateKeyPath != null) { + map.put(OciConfig.CONFIG_KEY + ".auth.private-key-path", privateKeyPath); + } + if (region != null) { + map.put(OciConfig.CONFIG_KEY + ".auth.region", region); + } + return ConfigSources.create(map, "config-oci-auth-simple"); + } @BeforeEach void setUp() { - InjectionServices.globalBootstrap(Bootstrap.builder().config(Config.create()).build()); + registryManager = ServiceRegistryManager.create(); } @AfterEach void reset() { OciExtension.ociConfigFileName(null); - resetAll(); + if (registryManager != null) { + registryManager.shutdown(); + } } @Test @@ -84,7 +148,7 @@ void potentialAuthStrategies() { .get(OciConfig.CONFIG_KEY); cfg = OciConfig.create(config); assertThat(cfg.potentialAuthStrategies(), - contains( "config", "config-file", "instance-principals", "resource-principal")); + contains("config", "config-file", "instance-principals", "resource-principal")); config = createTestConfig(ociAuthConfigStrategies(null, "instance-principals", "auto")) .get(OciConfig.CONFIG_KEY); @@ -130,6 +194,7 @@ void bogusAuthStrategyAttempted() { assertThat(e.getMessage(), containsString("Configured: \"bogus\", expected one of:")); } + @Test void testBogusAuthStrategies() { Config config = createTestConfig(ociAuthConfigStrategies(null, "config", "bogus")) @@ -248,8 +313,9 @@ void ociYamlConfigFile() { optionalValue(equalTo("resource-principal"))); // note that we can't actually instantiate these when there is no auth provider configured in the environment - IllegalArgumentException e = (IllegalArgumentException) assertThrows(InjectionServiceProviderException.class, - () -> OciExtension.ociAuthenticationProvider().get()).getCause(); + IllegalArgumentException e = (IllegalArgumentException) assertThrows(ServiceRegistryException.class, + () -> OciExtension.ociAuthenticationProvider() + .get()).getCause(); assertThat(e.getMessage(), equalTo(OciAuthenticationDetailsProvider.TAG_RESOURCE_PRINCIPAL_VERSION + " environment variable missing")); assertThat(OciExtension.configuredAuthenticationDetailsProvider(false), @@ -267,11 +333,10 @@ void ociYamlConfigFile() { equalTo(ConfigFileAuthenticationDetailsProvider.class)); assertThat(OciExtension.configuredAuthenticationDetailsProvider(false), equalTo(ConfigFileAuthenticationDetailsProvider.class)); - } catch (InjectionServiceProviderException ispe) { + } catch (ServiceRegistryException ispe) { assertThat(ispe.getMessage(), - equalTo("Unable to activate: io.helidon.integrations.oci.sdk.runtime" - + ".OciAuthenticationDetailsProvider$$Injection$$Activator: service provider: " - + "OciAuthenticationDetailsProvider:ACTIVE")); + equalTo("Failed to list instances in InjectionPointProvider: " + + "io.helidon.integrations.oci.sdk.runtime.OciAuthenticationDetailsProvider")); assertThat(ispe.getCause().getMessage(), equalTo("No instances of com.oracle.bmc.auth.AbstractAuthenticationDetailsProvider available for use. " + "Verify your configuration named: oci")); @@ -290,9 +355,9 @@ void ociRawConfigShouldBeCached() { @Test void fallbackConfigSupplier() { Config fallbackCfg = Config.just( - ConfigSources.create( - Map.of("oci.auth", "config"), - "test-fallback-cfg")); + ConfigSources.create( + Map.of("oci.auth", "config"), + "test-fallback-cfg")); OciExtension.fallbackConfigSupplier(() -> fallbackCfg); assertThat("when there is no oci.yaml present then we should be looking at the fallback config", @@ -306,74 +371,4 @@ void fallbackConfigSupplier() { equalTo(ResourcePrincipalAuthenticationDetailsProvider.class)); } - static Config createTestConfig(MapConfigSource.Builder... builders) { - return Config.builder(builders) - .disableEnvironmentVariablesSource() - .disableSystemPropertiesSource() - .build(); - } - - static MapConfigSource.Builder basicTestingConfigSource() { - return ConfigSources.create( - Map.of("inject.permits-dynamic", "true", - "inject.activation-logs", "true" - ), "config-basic"); - } - - static MapConfigSource.Builder ociAuthConfigStrategies(String strategy, - String... strategies) { - Map map = new HashMap<>(); - if (strategy != null) { - map.put(OciConfig.CONFIG_KEY + ".auth-strategy", strategy); - } - if (strategies != null && strategies.length != 0) { - map.put(OciConfig.CONFIG_KEY + ".auth-strategies", String.join(",", strategies)); - } - return ConfigSources.create(map, "config-oci-auth-strategies"); - } - - static MapConfigSource.Builder ociAuthConfigFile(String configPath, - String profile) { - Map map = new HashMap<>(); - if (configPath != null) { - map.put(OciConfig.CONFIG_KEY + ".config.path", configPath); - } - if (profile != null) { - map.put(OciConfig.CONFIG_KEY + ".config.profile", String.join(",", profile)); - } - return ConfigSources.create(map, "config-oci-auth-config"); - } - - static MapConfigSource.Builder ociAuthSimpleConfig(String tenantId, - String userId, - String passPhrase, - String fingerPrint, - String privateKey, - String privateKeyPath, - String region) { - Map map = new HashMap<>(); - if (tenantId != null) { - map.put(OciConfig.CONFIG_KEY + ".auth.tenant-id", tenantId); - } - if (userId != null) { - map.put(OciConfig.CONFIG_KEY + ".auth.user-id", userId); - } - if (passPhrase != null) { - map.put(OciConfig.CONFIG_KEY + ".auth.passphrase", passPhrase); - } - if (fingerPrint != null) { - map.put(OciConfig.CONFIG_KEY + ".auth.fingerprint", fingerPrint); - } - if (privateKey != null) { - map.put(OciConfig.CONFIG_KEY + ".auth.private-key", privateKey); - } - if (privateKeyPath != null) { - map.put(OciConfig.CONFIG_KEY + ".auth.private-key-path", privateKeyPath); - } - if (region != null) { - map.put(OciConfig.CONFIG_KEY + ".auth.region", region); - } - return ConfigSources.create(map, "config-oci-auth-simple"); - } - } diff --git a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProviderTest.java b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProviderTest.java index 89e73cffdd3..9cb730f170f 100644 --- a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProviderTest.java +++ b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciRegionProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,80 +16,102 @@ package io.helidon.integrations.oci.sdk.runtime; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +import io.helidon.common.config.GlobalConfig; import io.helidon.common.types.AccessModifier; +import io.helidon.common.types.ElementKind; import io.helidon.common.types.TypeName; import io.helidon.config.Config; -import io.helidon.inject.api.ContextualServiceQuery; -import io.helidon.inject.api.ElementKind; -import io.helidon.inject.api.InjectionPointInfo; -import io.helidon.inject.api.InjectionServices; -import io.helidon.inject.api.InjectionServiceProviderException; -import io.helidon.inject.api.Qualifier; -import io.helidon.inject.api.ServiceInfoCriteria; -import io.helidon.inject.api.ServiceProvider; -import io.helidon.inject.api.Services; +import io.helidon.service.registry.Dependency; +import io.helidon.service.registry.FactoryType; +import io.helidon.service.registry.Lookup; +import io.helidon.service.registry.Qualifier; +import io.helidon.service.registry.Service; +import io.helidon.service.registry.ServiceRegistry; +import io.helidon.service.registry.ServiceRegistryConfig; +import io.helidon.service.registry.ServiceRegistryException; +import io.helidon.service.registry.ServiceRegistryManager; import com.oracle.bmc.Region; +import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; -import static io.helidon.common.testing.junit5.OptionalMatcher.optionalValue; -import static io.helidon.inject.testing.InjectionTestingSupport.resetAll; -import static io.helidon.inject.testing.InjectionTestingSupport.testableServices; -import static org.hamcrest.CoreMatchers.equalTo; +import static io.helidon.common.testing.junit5.OptionalMatcher.optionalPresent; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; import static org.junit.jupiter.api.Assertions.assertThrows; +@SuppressWarnings("removal") class OciRegionProviderTest { - InjectionServices injectionServices; - Services services; + static ServiceRegistryManager registryManager; + static ServiceRegistry registry; @AfterAll static void tearDown() { - resetAll(); + if (registryManager != null) { + registryManager.shutdown(); + } + registryManager = null; + registry = null; } - void resetWith(Config config) { - resetAll(); - this.injectionServices = testableServices(config); - this.services = injectionServices.services(); + void resetWith(Config config, ServiceRegistryConfig injectionConfig) { + if (registryManager != null) { + registryManager.shutdown(); + } + registryManager = ServiceRegistryManager.create(injectionConfig); + OciExtension.serviceRegistry(registryManager); + registry = registryManager.registry(); + GlobalConfig.config(() -> config, true); } @Test void regionProviderService() { Config config = OciExtensionTest.createTestConfig( - OciExtensionTest.basicTestingConfigSource(), OciExtensionTest.ociAuthConfigStrategies(OciAuthenticationDetailsProvider.VAL_AUTO), OciExtensionTest.ociAuthSimpleConfig("tenant", "user", "phrase", "fp", null, null, "region")); - resetWith(config); + resetWith(config, ServiceRegistryConfig.create()); - ServiceProvider regionProvider = InjectionServices.realizedServices() - .lookupFirst(Region.class, false).orElseThrow(); - assertThrows(InjectionServiceProviderException.class, - regionProvider::get); + Supplier regionSupplier = registryManager + .registry() + .supply(Lookup.builder().addContract(Region.class).build()); + assertThrows(ServiceRegistryException.class, + regionSupplier::get); TypeName regionType = TypeName.create(Region.class); - ContextualServiceQuery query = ContextualServiceQuery.create( - InjectionPointInfo.builder() - .ipType(regionType) - .ipName("region") - .serviceTypeName(TypeName.create("io.helidon.Whatever")) + Lookup query = Lookup.create( + Dependency.builder() + .contract(regionType) + .descriptorConstant("TEST_ONLY") + .descriptor(TypeName.create("io.helidon.Whatever")) + .typeName(regionType) + .service(TypeName.create("io.helidon.Whatever")) + .name("region") .elementKind(ElementKind.METHOD) - .elementName("m") - .elementTypeName(regionType) - .baseIdentity("m") - .id("m1") .access(AccessModifier.PUBLIC) .addQualifier(Qualifier.createNamed("us-phoenix-1")) - .dependencyToServiceInfo(ServiceInfoCriteria.builder() - .addContractImplemented(regionType) - .addQualifier(Qualifier.createNamed("us-phoenix-1")) - .build()) - .build(), - false); - assertThat(regionProvider.first(query), - optionalValue(equalTo(Region.US_PHOENIX_1))); - } + .build()); + + Service.InjectionPointFactory regionProvider = registryManager + .registry() + .get(Lookup.builder() + .addFactoryType(FactoryType.INJECTION_POINT) + .addContract(Region.class) + .build()); + Optional> regionInstance = regionProvider.first(query); + assertThat(regionInstance, optionalPresent()); + Service.QualifiedInstance regionQualifiedInstance = regionInstance.get(); + Region region = regionQualifiedInstance.get(); + Set qualifiers = regionQualifiedInstance.qualifiers(); + + assertThat(region, is(Region.US_PHOENIX_1)); + assertThat(qualifiers, contains(Qualifier.createNamed(Region.US_PHOENIX_1.getRegionId()))); + } } diff --git a/integrations/oci/sdk/tests/pom.xml b/integrations/oci/sdk/tests/pom.xml index 2dd201bae54..2df6e9cdb6f 100644 --- a/integrations/oci/sdk/tests/pom.xml +++ b/integrations/oci/sdk/tests/pom.xml @@ -31,7 +31,7 @@ helidon-integrations-oci-sdk-tests-project Helidon Integrations OCI Injection Tests - Helidon Injection Framework Testing for the OCI SDK + Helidon Service Registry Framework Testing for the OCI SDK pom diff --git a/integrations/oci/sdk/tests/test-application/pom.xml b/integrations/oci/sdk/tests/test-application/pom.xml index 2c0fd7a82bd..f3fdf73157d 100644 --- a/integrations/oci/sdk/tests/test-application/pom.xml +++ b/integrations/oci/sdk/tests/test-application/pom.xml @@ -104,13 +104,30 @@ true + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-processor + helidon-integrations-oci-sdk-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.integrations.oci.sdk + helidon-integrations-oci-sdk-codegen + ${helidon.version} + + diff --git a/integrations/oci/sdk/tests/test-module1/pom.xml b/integrations/oci/sdk/tests/test-module1/pom.xml index fc2de120a2d..033a9e6b3ba 100644 --- a/integrations/oci/sdk/tests/test-module1/pom.xml +++ b/integrations/oci/sdk/tests/test-module1/pom.xml @@ -81,13 +81,30 @@ true + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-processor + helidon-integrations-oci-sdk-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.integrations.oci.sdk + helidon-integrations-oci-sdk-codegen + ${helidon.version} + + diff --git a/integrations/oci/sdk/tests/test-module1/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module1/AServiceUsingObjectStorage.java b/integrations/oci/sdk/tests/test-module1/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module1/AServiceUsingObjectStorage.java index 7180393994d..5408b693f8a 100644 --- a/integrations/oci/sdk/tests/test-module1/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module1/AServiceUsingObjectStorage.java +++ b/integrations/oci/sdk/tests/test-module1/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module1/AServiceUsingObjectStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,24 +17,23 @@ package io.helidon.integrations.oci.sdk.tests.test.module1; import java.util.Objects; +import java.util.function.Supplier; + +import io.helidon.service.registry.Service; import com.oracle.bmc.objectstorage.ObjectStorage; import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; -@Singleton +@Service.Singleton class AServiceUsingObjectStorage { private final ObjectStorage objStorageClient; - private final Provider standbyObjStorageClientProvider; + private final Supplier standbyObjStorageClientProvider; - @Inject + @Service.Inject AServiceUsingObjectStorage(ObjectStorage objStorage, - @Named("StandbyProfile") Provider standbyObjStorageProvider) { + @Service.Named("StandbyProfile") Supplier standbyObjStorageProvider) { this.objStorageClient = Objects.requireNonNull(objStorage); this.standbyObjStorageClientProvider = Objects.requireNonNull(standbyObjStorageProvider); } diff --git a/integrations/oci/sdk/tests/test-module2/pom.xml b/integrations/oci/sdk/tests/test-module2/pom.xml index 00599b081b6..f68da5f88e3 100644 --- a/integrations/oci/sdk/tests/test-module2/pom.xml +++ b/integrations/oci/sdk/tests/test-module2/pom.xml @@ -81,13 +81,30 @@ true + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + io.helidon.integrations.oci.sdk - helidon-integrations-oci-sdk-processor + helidon-integrations-oci-sdk-codegen ${helidon.version} + + + io.helidon.codegen + helidon-codegen-apt + ${helidon.version} + + + io.helidon.integrations.oci.sdk + helidon-integrations-oci-sdk-codegen + ${helidon.version} + + diff --git a/integrations/oci/sdk/tests/test-module2/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module2/AnotherServiceUsingObjectStorage.java b/integrations/oci/sdk/tests/test-module2/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module2/AnotherServiceUsingObjectStorage.java index 8c6b5eeac24..3ae28f0f317 100644 --- a/integrations/oci/sdk/tests/test-module2/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module2/AnotherServiceUsingObjectStorage.java +++ b/integrations/oci/sdk/tests/test-module2/src/main/java/io/helidon/integrations/oci/sdk/tests/test/module2/AnotherServiceUsingObjectStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,24 +17,23 @@ package io.helidon.integrations.oci.sdk.tests.test.module2; import java.util.Objects; +import java.util.function.Supplier; + +import io.helidon.service.registry.Service; import com.oracle.bmc.objectstorage.ObjectStorage; import com.oracle.bmc.objectstorage.requests.GetNamespaceRequest; import com.oracle.bmc.objectstorage.responses.GetNamespaceResponse; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Provider; -import jakarta.inject.Singleton; -@Singleton +@Service.Singleton class AnotherServiceUsingObjectStorage { - @Inject + @Service.Inject ObjectStorage objStorageClient; - Provider standbyObjStorageClientProvider; + Supplier standbyObjStorageClientProvider; - @Inject - void setStandbyObjectStorageProvider(@Named("StandbyProfile") Provider standbyObjStorageClientProvider) { + @Service.Inject + void setStandbyObjectStorageProvider(@Service.Named("StandbyProfile") Supplier standbyObjStorageClientProvider) { this.standbyObjStorageClientProvider = Objects.requireNonNull(standbyObjStorageClientProvider); } diff --git a/pom.xml b/pom.xml index 2e5c8752724..2f7fc94d607 100644 --- a/pom.xml +++ b/pom.xml @@ -218,7 +218,6 @@ health helidon http - inject integrations jersey licensing diff --git a/service/README.md b/service/README.md index 4dcb84a7813..f28aac29bac 100644 --- a/service/README.md +++ b/service/README.md @@ -258,7 +258,7 @@ the specified qualifiers. One qualifier is provided out-of-the-box - the `@Service.Named` (and `@Service.NamedByType` which does the same thing, only the name is the fully qualified class name of the provided class). -Named instances are used by some feature of Helidon Inject itself. +Named instances are used by some features of Helidon Service Registry itself. # Service Lifecycle @@ -300,7 +300,7 @@ There may be cases, where this is not sufficient: - the provided contract is not an interface - the provided instance may not be created at all (i.e. it is optional) -This can be done by implementing one of the factory interfaces Helidon Inject supports: +This can be done by implementing one of the factory interfaces Helidon Service Registry supports: - `java.util.function.Supplier` - a factory that supplies a single instance (can also be `Supplier>`) - `io.helidon.service.registry.Service.ServicesFactory` - a factory that creates zero or more contract implementations diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/InterceptionStrategy.java b/service/codegen/src/main/java/io/helidon/service/codegen/InterceptionStrategy.java index 583fbd2181c..5b1cf895c00 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/InterceptionStrategy.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/InterceptionStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * Possible strategies to interception. * Whether interception is supported, and this is honored depends on implementation. *

- * The strategy is (in Helidon inject) only honored at compilation time. At runtime, it can only be enabled or disabled. + * The strategy is (in Helidon service registry) only honored at compilation time. At runtime, it can only be enabled or disabled. */ public enum InterceptionStrategy { /** diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/ServiceCodegenTypes.java b/service/codegen/src/main/java/io/helidon/service/codegen/ServiceCodegenTypes.java index 266a5e7e108..d9cdb396d36 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/ServiceCodegenTypes.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/ServiceCodegenTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -125,6 +125,11 @@ public final class ServiceCodegenTypes { */ public static final TypeName SERVICE_QUALIFIED_FACTORY = TypeName.create( "io.helidon.service.registry.Service.QualifiedFactory"); + /** + * {@link io.helidon.common.types.TypeName} for {@code io.helidon.service.registry.Service.QualifiedInstance}. + */ + public static final TypeName SERVICE_QUALIFIED_INSTANCE = TypeName.create( + "io.helidon.service.registry.Service.QualifiedInstance"); /** * {@link io.helidon.common.types.TypeName} for {@code io.helidon.service.registry.Dependency}. */ @@ -186,6 +191,11 @@ public final class ServiceCodegenTypes { */ public static final TypeName SERVICE_LOADER_DESCRIPTOR = TypeName.create("io.helidon.service.registry.ServiceLoader__ServiceDescriptor"); + /** + * {@link io.helidon.common.types.TypeName} for {@code io.helidon.service.registry.Lookup}. + */ + public static final TypeName SERVICE_LOOKUP = + TypeName.create("io.helidon.service.registry.Lookup"); /** * {@link io.helidon.common.types.TypeName} for * {@code io.helidon.service.registry.GeneratedService.PerInstanceDescriptor}. diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectAssignment.java b/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectAssignment.java index d85b837cd3a..bf747077ffa 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectAssignment.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectAssignment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ public interface InjectAssignment { * * @param typeName type of the processed injection point, may be a generic type such as {@link java.util.List}, * {@link java.util.Optional} (these are the types expected to be supported) - * @param valueSource code that obtains value from Helidon injection (if this method returns a non-empty optional, + * @param valueSource code that obtains value from Helidon Service Registry (if this method returns a non-empty optional, * the provided value will be an {@link java.util.Optional} {@link java.util.function.Supplier}, * {@link java.util.List} of {@link java.util.function.Supplier}, or a {@link java.util.function.Supplier} * as returned by the {@link Assignment#usedType()}; diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectCodegenObserverProvider.java b/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectCodegenObserverProvider.java index 40e6b50703c..31da9ce7246 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectCodegenObserverProvider.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/spi/InjectCodegenObserverProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,7 @@ default Set> supportedOptions() { } /** - * Create a new observer based on the Helidon Inject code generation context. + * Create a new observer based on the Helidon Service Registry code generation context. * * @param context code generation context for this code generation session * @return a new observer diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/spi/RegistryCodegenExtensionProvider.java b/service/codegen/src/main/java/io/helidon/service/codegen/spi/RegistryCodegenExtensionProvider.java index d0378aec64e..b597407f919 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/spi/RegistryCodegenExtensionProvider.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/spi/RegistryCodegenExtensionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ import io.helidon.service.codegen.RegistryCodegenContext; /** - * A {@link java.util.ServiceLoader} provider interface for extensions of code generators for Helidon Inject. + * A {@link java.util.ServiceLoader} provider interface for extensions of code generators for Helidon Service Registry. * The difference between this extension and a general {@link io.helidon.codegen.spi.CodegenExtensionProvider} is that * this provider has access to {@link io.helidon.service.codegen.RegistryCodegenContext}. */ diff --git a/service/codegen/src/main/java/io/helidon/service/codegen/spi/package-info.java b/service/codegen/src/main/java/io/helidon/service/codegen/spi/package-info.java index 251312c17a1..892399d92a3 100644 --- a/service/codegen/src/main/java/io/helidon/service/codegen/spi/package-info.java +++ b/service/codegen/src/main/java/io/helidon/service/codegen/spi/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,6 @@ */ /** - * SPI for extending code generation capabilities of Helidon Inject. + * SPI for extending code generation capabilities of Helidon Service Registry. */ package io.helidon.service.codegen.spi; diff --git a/service/registry/src/main/java/io/helidon/service/registry/Interception.java b/service/registry/src/main/java/io/helidon/service/registry/Interception.java index 4926b361521..ea194f62783 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/Interception.java +++ b/service/registry/src/main/java/io/helidon/service/registry/Interception.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024 Oracle and/or its affiliates. + * Copyright (c) 2023, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ /** * Interception annotations and types. - * This is the entry point for any annotation and type related to interception in Helidon Inject. + * This is the entry point for any annotation and type related to interception in Helidon Service Registry. */ public final class Interception { private Interception() { diff --git a/service/registry/src/main/java/io/helidon/service/registry/RegistryStartupProvider.java b/service/registry/src/main/java/io/helidon/service/registry/RegistryStartupProvider.java index 0325fc9d4be..9a56ce16075 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/RegistryStartupProvider.java +++ b/service/registry/src/main/java/io/helidon/service/registry/RegistryStartupProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Oracle and/or its affiliates. + * Copyright (c) 2024, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,14 +72,14 @@ public void shutdown() { registryManager.shutdown(); } catch (Exception e) { logger.log(System.Logger.Level.ERROR, - "Failed to shutdown Helidon Inject registry", + "Failed to shutdown Helidon Service Registry registry", e); } } @Override public String toString() { - return "Helidon Inject shutdown handler"; + return "Helidon Service Registry shutdown handler"; } } } diff --git a/service/registry/src/main/java/io/helidon/service/registry/ScopedRegistryImpl.java b/service/registry/src/main/java/io/helidon/service/registry/ScopedRegistryImpl.java index aeef9477ff5..8aefb1e8633 100644 --- a/service/registry/src/main/java/io/helidon/service/registry/ScopedRegistryImpl.java +++ b/service/registry/src/main/java/io/helidon/service/registry/ScopedRegistryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Oracle and/or its affiliates. + * Copyright (c) 2024, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ /** * Services for a specific scope. - * This type is owned by Helidon Injection, and cannot be customized. + * This type is owned by Helidon Service Registry, and cannot be customized. * When a scope is properly accessible through its {@link Service.ScopeHandler}, * {@link #activate()} * must be invoked by its control, to make sure all eager services are correctly activated. diff --git a/service/tests/codegen/src/test/java/io/helidon/service/tests/codegen/ServiceCodegenTypesTest.java b/service/tests/codegen/src/test/java/io/helidon/service/tests/codegen/ServiceCodegenTypesTest.java index bb6b76fa664..02227499075 100644 --- a/service/tests/codegen/src/test/java/io/helidon/service/tests/codegen/ServiceCodegenTypesTest.java +++ b/service/tests/codegen/src/test/java/io/helidon/service/tests/codegen/ServiceCodegenTypesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Oracle and/or its affiliates. + * Copyright (c) 2024, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ import io.helidon.service.registry.InterceptionException; import io.helidon.service.registry.InterceptionInvoker; import io.helidon.service.registry.InterceptionMetadata; +import io.helidon.service.registry.Lookup; import io.helidon.service.registry.Qualifier; import io.helidon.service.registry.RegistryStartupProvider; import io.helidon.service.registry.Service; @@ -123,6 +124,8 @@ void testTypes() { checkField(toCheck, checked, fields, "SERVICE_REGISTRY_MANAGER", ServiceRegistryManager.class); checkField(toCheck, checked, fields, "DEPENDENCY_CARDINALITY", DependencyCardinality.class); checkField(toCheck, checked, fields, "SERVICE_LOADER_DESCRIPTOR", ServiceLoader__ServiceDescriptor.class); + checkField(toCheck, checked, fields, "SERVICE_LOOKUP", Lookup.class); + checkField(toCheck, checked, fields, "SERVICE_QUALIFIED_INSTANCE", Service.QualifiedInstance.class); // api.Interception.* checkField(toCheck, checked, fields, "INTERCEPTION_INTERCEPTED", Interception.Intercepted.class); diff --git a/service/tests/maven-plugin/src/it/projects/test1/postbuild.groovy b/service/tests/maven-plugin/src/it/projects/test1/postbuild.groovy index aaeb9dcaca5..0a0f54e500e 100644 --- a/service/tests/maven-plugin/src/it/projects/test1/postbuild.groovy +++ b/service/tests/maven-plugin/src/it/projects/test1/postbuild.groovy @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. + * Copyright (c) 2022, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ JUnitLauncher.builder() .parameter("basedir", basedir.getAbsolutePath()) .reportsDir(basedir) .outputFile(new File(basedir, "test.log")) - .suiteId("helidon-inject-maven-plugin-it-test1") - .suiteDisplayName("Helidon Inject Maven Plugin Integration Test 1") + .suiteId("helidon-service-maven-plugin-it-test1") + .suiteDisplayName("Helidon Service Maven Plugin Integration Test 1") .build() .launch() diff --git a/service/tests/maven-plugin/src/it/projects/test2/postbuild.groovy b/service/tests/maven-plugin/src/it/projects/test2/postbuild.groovy index 39aa4086ed9..91cd1232284 100644 --- a/service/tests/maven-plugin/src/it/projects/test2/postbuild.groovy +++ b/service/tests/maven-plugin/src/it/projects/test2/postbuild.groovy @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. + * Copyright (c) 2022, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ JUnitLauncher.builder() .parameter("basedir", basedir.getAbsolutePath()) .reportsDir(basedir) .outputFile(new File(basedir, "test.log")) - .suiteId("helidon-inject-maven-plugin-it-test2") - .suiteDisplayName("Helidon Inject Maven Plugin Integration Test 2") + .suiteId("helidon-service-maven-plugin-it-test2") + .suiteDisplayName("Helidon Service Maven Plugin Integration Test 2") .build() .launch() diff --git a/service/tests/maven-plugin/src/it/projects/test3/postbuild.groovy b/service/tests/maven-plugin/src/it/projects/test3/postbuild.groovy index fcf3d319c86..875af145344 100644 --- a/service/tests/maven-plugin/src/it/projects/test3/postbuild.groovy +++ b/service/tests/maven-plugin/src/it/projects/test3/postbuild.groovy @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. + * Copyright (c) 2022, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ JUnitLauncher.builder() .parameter("basedir", basedir.getAbsolutePath()) .reportsDir(basedir) .outputFile(new File(basedir, "test.log")) - .suiteId("helidon-inject-maven-plugin-it-test3") - .suiteDisplayName("Helidon Inject Maven Plugin Integration Test 3") + .suiteId("helidon-service-maven-plugin-it-test3") + .suiteDisplayName("Helidon Service Maven Plugin Integration Test 3") .build() .launch() diff --git a/tests/integration/packaging/mp-1/pom.xml b/tests/integration/packaging/mp-1/pom.xml index 9053497177b..7db967a86a5 100644 --- a/tests/integration/packaging/mp-1/pom.xml +++ b/tests/integration/packaging/mp-1/pom.xml @@ -1,6 +1,6 @@ - io.helidon.inject:helidon-inject-runtime - io.helidon.inject.configdriven:helidon-configdriven-runtime - - - - true - - - - diff --git a/webserver/webserver/src/main/java/io/helidon/webserver/RouterImpl.java b/webserver/webserver/src/main/java/io/helidon/webserver/RouterImpl.java index c0b5df7020e..63fc1a7f454 100644 --- a/webserver/webserver/src/main/java/io/helidon/webserver/RouterImpl.java +++ b/webserver/webserver/src/main/java/io/helidon/webserver/RouterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024 Oracle and/or its affiliates. + * Copyright (c) 2022, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -84,7 +84,6 @@ public RouterImpl build() { public Router.Builder addRouting(io.helidon.common.Builder routing) { var previous = this.routings.put(routing.getClass(), routing); if (previous != null) { - Thread.dumpStack(); LOGGER.log(System.Logger.Level.WARNING, "Second routing of the same type is registered. " + "The first instance will be ignored. Type: " + routing.getClass().getName()); }