Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preparation for Pico Extensibility Enhancements #6936

Merged
merged 4 commits into from
Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ public final class CommonQualifiers {
*/
public static final TypeName NAMED = TypeNameDefault.create(Named.class);

/**
* Represents a wildcard (i.e., matches anything).
*/
public static final String WILDCARD = "*";

/**
* Represents a wildcard {@link #NAMED} qualifier.
*/
public static final QualifierAndValue WILDCARD_NAMED = QualifierAndValueDefault.createNamed("*");
public static final QualifierAndValue WILDCARD_NAMED = QualifierAndValueDefault.createNamed(WILDCARD);

private CommonQualifiers() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ default void rootProvider(ServiceProvider<T> rootProvider) {
throw new UnsupportedOperationException();
}

/**
* Returns the previously assigned {@link PicoServices} instance.
*
* @param expected true if the result is expected to be non-empty
* @return the previously assigned pico services instance, or empty if never assigned
*
* @see #picoServices(Optional)
*/
Optional<PicoServices> picoServices(boolean expected);

/**
* 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 PicoServices#picoServices()} to ascertain the instance.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,7 @@ public void onPhaseEvent(Event event,
Phase phase) {
if (phase == Phase.POST_BIND_ALL_MODULES) {
assertIsInitializing();
PicoServices picoServices = picoServices();
assert (picoServices != null);
PicoServices picoServices = picoServices(true).orElseThrow();

if (Phase.INIT == currentActivationPhase()) {
LogEntryAndResult logEntryAndResult = createLogEntryAndResult(Phase.PENDING);
Expand Down Expand Up @@ -804,7 +803,7 @@ private Optional<AbstractConfiguredServiceProvider<T, CB>> innerPreActivateManag

// override our service info
instance.serviceInfo(newServiceInfo);
instance.picoServices(Optional.of(picoServices()));
instance.picoServices(picoServices(true));
instance.rootProvider(this);

if (logger().isLoggable(System.Logger.Level.DEBUG)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ public DependenciesInfo dependencies() {
}

@Override
public PicoServices picoServices() {
return delegate.picoServices();
public Optional<PicoServices> picoServices(boolean expected) {
return delegate.picoServices(expected);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ protected void innerExecute() {
: null;
String moduleInfoModuleName = getThisModuleName();
Optional<ServiceProvider<ModuleComponent>> moduleSp = lookupThisModule(moduleInfoModuleName, services, false);
String packageName = determinePackageName(moduleSp, serviceTypeNames, descriptor, true);
String packageName = determinePackageName(moduleSp, serviceTypeNames, Optional.ofNullable(descriptor), true);

CodeGenPaths codeGenPaths = CodeGenPathsDefault.builder()
.generatedSourcesPath(getGeneratedSourceDirectory().getPath())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,16 @@ public void execute() throws MojoExecutionException {
/**
* 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
* @param optModuleSp the module service provider
* @param typeNames the type names
* @param optDescriptor 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<ServiceProvider<ModuleComponent>> optModuleSp,
Collection<TypeName> typeNames,
ModuleInfoDescriptor descriptor,
boolean persistIt) {
String determinePackageName(Optional<ServiceProvider<ModuleComponent>> optModuleSp,
Collection<TypeName> typeNames,
Optional<ModuleInfoDescriptor> optDescriptor,
boolean persistIt) {
String packageName = getPackageName();
if (packageName == null) {
// check for the existence of the file
Expand All @@ -281,8 +281,10 @@ protected String determinePackageName(Optional<ServiceProvider<ModuleComponent>>
ServiceProvider<ModuleComponent> moduleSp = optModuleSp.orElse(null);
if (moduleSp != null) {
packageName = TypeNameDefault.createFromTypeName(moduleSp.serviceInfo().serviceTypeName()).packageName();
} else if (optDescriptor.isPresent()) {
packageName = toSuggestedGeneratedPackageName(optDescriptor.get(), typeNames, PicoServicesConfig.NAME);
} else {
packageName = toSuggestedGeneratedPackageName(descriptor, typeNames, PicoServicesConfig.NAME);
packageName = toSuggestedGeneratedPackageName(typeNames, PicoServicesConfig.NAME);
}
}

Expand Down
18 changes: 18 additions & 0 deletions pico/processor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,22 @@
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.helidon.builder</groupId>
<artifactId>helidon-builder-processor</artifactId>
<version>${helidon.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
*
* @see ActiveProcessorUtils
*/
final class GeneralProcessorUtils {
public final class GeneralProcessorUtils {
private GeneralProcessorUtils() {
}

Expand Down Expand Up @@ -335,7 +335,7 @@ static Set<QualifierAndValue> toQualifiers(TypedElementInfo element,
* @param typeName the type name to check
* @return true if the provided type is a provider type.
*/
static boolean isProviderType(TypeName typeName) {
public static boolean isProviderType(TypeName typeName) {
String name = typeName.name();
return (name.equals(TypeNames.JAKARTA_PROVIDER)
|| name.equals(TypeNames.JAVAX_PROVIDER)
Expand All @@ -355,27 +355,34 @@ static boolean hasValue(String val) {
/**
* Looks for either a jakarta or javax annotation.
*
* @param jakartaAnno the jakarta annotation class type
* @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<? extends AnnotationAndValue> findFirst(Class<? extends Annotation> jakartaAnno,
Collection<? extends AnnotationAndValue> annotations) {
return findFirst(jakartaAnno.getName(), annotations);
public static Optional<? extends AnnotationAndValue> findFirst(Class<? extends Annotation> annoType,
Collection<? extends AnnotationAndValue> annotations) {
return findFirst(annoType.getName(), annotations);
}

static Optional<? extends AnnotationAndValue> findFirst(String jakartaAnnoName,
static Optional<? extends AnnotationAndValue> findFirst(String annoTypeName,
Collection<? extends AnnotationAndValue> annotations) {
if (annotations == null) {
return Optional.empty();
}

Optional<? extends AnnotationAndValue> anno = AnnotationAndValueDefault.findFirst(jakartaAnnoName, annotations);
Optional<? extends AnnotationAndValue> anno = AnnotationAndValueDefault.findFirst(annoTypeName, annotations);
if (anno.isPresent()) {
return anno;
}

return AnnotationAndValueDefault.findFirst(TypeTools.oppositeOf(jakartaAnnoName), annotations);
boolean startsWithJakarta = annoTypeName.startsWith(TypeNames.PREFIX_JAKARTA);
boolean startsWithJavax = !startsWithJakarta && annoTypeName.startsWith(TypeNames.PREFIX_JAVAX);

if (startsWithJakarta || startsWithJavax) {
return AnnotationAndValueDefault.findFirst(TypeTools.oppositeOf(annoTypeName), annotations);
}

return Optional.empty();
}

static ServiceInfoBasics toBasicServiceInfo(TypeInfo service) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
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;
Expand All @@ -38,6 +40,7 @@
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

import io.helidon.common.HelidonServiceLoader;
import io.helidon.common.types.AnnotationAndValue;
import io.helidon.common.types.AnnotationAndValueDefault;
import io.helidon.common.types.TypeInfo;
Expand All @@ -52,6 +55,9 @@
import io.helidon.pico.api.PicoServicesConfig;
import io.helidon.pico.api.QualifierAndValue;
import io.helidon.pico.api.ServiceInfoBasics;
import io.helidon.pico.processor.spi.PicoAnnotationProcessorObserver;
import io.helidon.pico.processor.spi.ProcessingEvent;
import io.helidon.pico.processor.spi.ProcessingEventDefault;
import io.helidon.pico.runtime.Dependencies;
import io.helidon.pico.tools.ActivatorCreatorCodeGen;
import io.helidon.pico.tools.ActivatorCreatorCodeGenDefault;
Expand Down Expand Up @@ -192,6 +198,8 @@ public boolean process(Set<? extends TypeElement> annotations,
doFiler(services);
}

notifyObservers();

return MAYBE_ANNOTATIONS_CLAIMED_BY_THIS_PROCESSOR;
} catch (Throwable t) {
ToolsException exc = new ToolsException("Error while processing: " + t
Expand Down Expand Up @@ -461,13 +469,13 @@ protected void processExtensions(ServicesToProcess services,
/**
* Finds the first jakarta or javax annotation matching the given jakarta annotation class name.
*
* @param jakartaAnnoName the jakarta annotation class name
* @param annotations all of the annotations to search through
* @param annoTypeName the annotation class name
* @param annotations all of the annotations to search through
* @return the annotation, or empty if not found
*/
protected Optional<? extends AnnotationAndValue> findFirst(String jakartaAnnoName,
protected Optional<? extends AnnotationAndValue> findFirst(String annoTypeName,
Collection<? extends AnnotationAndValue> annotations) {
return GeneralProcessorUtils.findFirst(jakartaAnnoName, annotations);
return GeneralProcessorUtils.findFirst(annoTypeName, annotations);
}

private ServicesToProcess toServicesToProcess(Set<TypeInfo> typesToCodeGenerate,
Expand Down Expand Up @@ -641,6 +649,30 @@ private void gatherInjectionPoints(Dependencies.BuilderContinuation builder,
// service.superTypeInfo().ifPresent(it -> gatherInjectionPoints(builder, it, allElementsOfInterest, false));
}

private void notifyObservers() {
List<PicoAnnotationProcessorObserver> observers = HelidonServiceLoader.create(observerLoader()).asList();
if (!observers.isEmpty()) {
ProcessingEvent event = ProcessingEventDefault.builder()
.processingEnvironment(processingEnv)
.elementsOfInterest(allElementsOfInterestInThisModule)
.build();
observers.forEach(it -> it.onProcessingEvent(event));
}
}

private static ServiceLoader<PicoAnnotationProcessorObserver> observerLoader() {
try {
// note: it is important to use this class' CL since maven will not give us the "right" one.
return ServiceLoader.load(
PicoAnnotationProcessorObserver.class, PicoAnnotationProcessorObserver.class.getClassLoader());
} catch (ServiceConfigurationError e) {
// see issue #6261 - running inside the IDE?
// this version will use the thread ctx classloader
System.getLogger(PicoAnnotationProcessorObserver.class.getName()).log(System.Logger.Level.WARNING, e.getMessage(), e);
return ServiceLoader.load(PicoAnnotationProcessorObserver.class);
}
}

/**
* Processes all of the injection points for the provided typed element, accumulating the result in the provided builder
* continuation instance.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.pico.processor.spi;

/**
* Implementations of these are service-loaded by the {@link io.helidon.pico.processor.PicoAnnotationProcessor}, and will be
* called to be able to observe processing events.
*/
public interface PicoAnnotationProcessorObserver {

/**
* Called after a processing event that occurred in the {@link io.helidon.pico.processor.PicoAnnotationProcessor}.
*
* @param event the event
*/
void onProcessingEvent(ProcessingEvent event);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.pico.processor.spi;

import java.util.Optional;
import java.util.Set;

import javax.annotation.processing.ProcessingEnvironment;

import io.helidon.builder.Builder;
import io.helidon.common.types.TypedElementInfo;

/**
* Attributes that can be observed via {@link PicoAnnotationProcessorObserver}.
*/
@Builder
public interface ProcessingEvent {

/**
* Optionally, the active {@link ProcessingEnvironment} if it is available.
*
* @return the processing environment if it is available
*/
Optional<ProcessingEnvironment> processingEnvironment();

/**
* The {@link 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 pico APT
*/
Set<TypedElementInfo> elementsOfInterest();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Pico APT SPI package.
*/
package io.helidon.pico.processor.spi;
4 changes: 3 additions & 1 deletion pico/processor/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@
requires io.helidon.builder.processor;

exports io.helidon.pico.processor;
exports io.helidon.pico.processor.spi;

uses io.helidon.builder.processor.BuilderProcessor;
uses io.helidon.builder.processor.spi.TypeInfoCreatorProvider;
uses io.helidon.pico.processor.spi.PicoAnnotationProcessorObserver;
uses io.helidon.pico.tools.spi.InterceptorCreator;
uses io.helidon.pico.tools.spi.CustomAnnotationTemplateCreator;
uses io.helidon.builder.processor.spi.TypeInfoCreatorProvider;

provides javax.annotation.processing.Processor with
io.helidon.pico.processor.CustomAnnotationProcessor,
Expand Down
Loading