Skip to content

Commit

Permalink
Register @ConfigMappings directly into the Config builder
Browse files Browse the repository at this point in the history
(cherry picked from commit d6970e1)
  • Loading branch information
radcortez authored and geoand committed Sep 29, 2021
1 parent 5a4847b commit e3d45af
Show file tree
Hide file tree
Showing 14 changed files with 414 additions and 141 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.quarkus.arc.deployment;
package io.quarkus.deployment.builditem;

import java.util.Set;

import io.quarkus.builder.item.MultiBuildItem;
import io.quarkus.runtime.annotations.StaticInitSafe;

public final class ConfigClassBuildItem extends MultiBuildItem {
private final Class<?> configClass;
Expand Down Expand Up @@ -46,8 +47,12 @@ public boolean isProperties() {
return Type.PROPERTIES.equals(type);
}

public boolean isStaticInitSafe() {
return configClass.isAnnotationPresent(StaticInitSafe.class);
}

public enum Type {
MAPPING,
PROPERTIES;
PROPERTIES
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package io.quarkus.deployment.configuration;

import static io.quarkus.deployment.builditem.ConfigClassBuildItem.Type.MAPPING;
import static io.quarkus.deployment.builditem.ConfigClassBuildItem.Type.PROPERTIES;
import static java.util.Collections.emptySet;
import static org.eclipse.microprofile.config.inject.ConfigProperties.UNCONFIGURED_PREFIX;
import static org.jboss.jandex.AnnotationTarget.Kind.CLASS;
import static org.jboss.jandex.AnnotationTarget.Kind.FIELD;
import static org.jboss.jandex.AnnotationTarget.Kind.METHOD_PARAMETER;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.ClassType;
import org.jboss.jandex.DotName;
import org.jboss.jandex.MethodInfo;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.ConfigClassBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.ConfigMappingLoader;
import io.smallrye.config.ConfigMappingMetadata;

public class ConfigMappingUtils {
public static final DotName CONFIG_MAPPING_NAME = DotName.createSimple(ConfigMapping.class.getName());

private ConfigMappingUtils() {
}

@BuildStep
public static void generateConfigClasses(
CombinedIndexBuildItem combinedIndex,
BuildProducer<GeneratedClassBuildItem> generatedClasses,
BuildProducer<ReflectiveClassBuildItem> reflectiveClasses,
BuildProducer<ConfigClassBuildItem> configClasses,
DotName configAnnotation) {

for (AnnotationInstance instance : combinedIndex.getIndex().getAnnotations(configAnnotation)) {
AnnotationTarget target = instance.target();
AnnotationValue annotationPrefix = instance.value("prefix");

if (target.kind().equals(FIELD)) {
if (annotationPrefix != null && !annotationPrefix.asString().equals(UNCONFIGURED_PREFIX)) {
configClasses.produce(
toConfigClassBuildItem(instance, toClass(target.asField().type().name()),
annotationPrefix.asString()));
continue;
}
}

if (target.kind().equals(METHOD_PARAMETER)) {
if (annotationPrefix != null && !annotationPrefix.asString().equals(UNCONFIGURED_PREFIX)) {
ClassType classType = target.asMethodParameter().method().parameters()
.get(target.asMethodParameter().position()).asClassType();
configClasses
.produce(toConfigClassBuildItem(instance, toClass(classType.name()), annotationPrefix.asString()));
continue;
}
}

if (!target.kind().equals(CLASS)) {
continue;
}

Class<?> configClass = toClass(target.asClass().name());
String prefix = Optional.ofNullable(annotationPrefix).map(AnnotationValue::asString).orElse("");

List<ConfigMappingMetadata> configMappingsMetadata = ConfigMappingLoader.getConfigMappingsMetadata(configClass);
Set<String> generatedClassesNames = new HashSet<>();
Set<ClassInfo> mappingsInfo = new HashSet<>();
configMappingsMetadata.forEach(mappingMetadata -> {
generatedClasses.produce(
new GeneratedClassBuildItem(true, mappingMetadata.getClassName(), mappingMetadata.getClassBytes()));
reflectiveClasses
.produce(ReflectiveClassBuildItem.builder(mappingMetadata.getInterfaceType()).methods(true).build());
reflectiveClasses
.produce(ReflectiveClassBuildItem.builder(mappingMetadata.getClassName()).constructors(true).build());

for (Class<?> parent : getHierarchy(mappingMetadata.getInterfaceType())) {
reflectiveClasses.produce(ReflectiveClassBuildItem.builder(parent).methods(true).build());
}

generatedClassesNames.add(mappingMetadata.getClassName());

ClassInfo mappingInfo = combinedIndex.getIndex()
.getClassByName(DotName.createSimple(mappingMetadata.getInterfaceType().getName()));
if (mappingInfo != null) {
mappingsInfo.add(mappingInfo);
}
});

// For implicit converters
for (ClassInfo classInfo : mappingsInfo) {
for (MethodInfo method : classInfo.methods()) {
reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, method.returnType().name().toString()));
}
}

configClasses.produce(toConfigClassBuildItem(instance, configClass, generatedClassesNames, prefix));
}
}

private static Class<?> toClass(DotName dotName) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
return classLoader.loadClass(dotName.toString());
} catch (ClassNotFoundException e) {
throw new IllegalStateException("The class (" + dotName.toString() + ") cannot be created during deployment.", e);
}
}

private static ConfigClassBuildItem toConfigClassBuildItem(
AnnotationInstance instance,
Class<?> configClass,
String prefix) {
return toConfigClassBuildItem(instance, configClass, emptySet(), prefix);
}

private static ConfigClassBuildItem toConfigClassBuildItem(
AnnotationInstance instance,
Class<?> configClass,
Set<String> generatedClasses,
String prefix) {
if (instance.name().equals(CONFIG_MAPPING_NAME)) {
return new ConfigClassBuildItem(configClass, generatedClasses, prefix, MAPPING);
} else {
return new ConfigClassBuildItem(configClass, generatedClasses, prefix, PROPERTIES);
}
}

private static List<Class<?>> getHierarchy(Class<?> mapping) {
List<Class<?>> interfaces = new ArrayList<>();
for (Class<?> i : mapping.getInterfaces()) {
interfaces.add(i);
interfaces.addAll(getHierarchy(i));
}
return interfaces;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
import io.quarkus.runtime.configuration.RuntimeConfigSource;
import io.quarkus.runtime.configuration.RuntimeConfigSourceFactory;
import io.quarkus.runtime.configuration.RuntimeConfigSourceProvider;
import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
import io.smallrye.config.Converters;
import io.smallrye.config.PropertiesConfigSource;
import io.smallrye.config.SmallRyeConfig;
Expand Down Expand Up @@ -179,6 +180,8 @@ public final class RunTimeConfigurationGenerator {
static final MethodDescriptor CU_ADD_SOURCE_FACTORY_PROVIDER = MethodDescriptor.ofMethod(ConfigUtils.class,
"addSourceFactoryProvider",
void.class, SmallRyeConfigBuilder.class, ConfigSourceFactoryProvider.class);
static final MethodDescriptor CU_WITH_MAPPING = MethodDescriptor.ofMethod(ConfigUtils.class, "addMapping",
void.class, SmallRyeConfigBuilder.class, String.class, String.class);

static final MethodDescriptor RCS_NEW = MethodDescriptor.ofConstructor(RuntimeConfigSource.class, String.class);
static final MethodDescriptor RCSP_NEW = MethodDescriptor.ofConstructor(RuntimeConfigSourceProvider.class, String.class);
Expand Down Expand Up @@ -306,6 +309,8 @@ public static final class GenerateOperation implements AutoCloseable {
final Set<String> runtimeConfigSources;
final Set<String> runtimeConfigSourceProviders;
final Set<String> runtimeConfigSourceFactories;
final Set<ConfigClassWithPrefix> staticConfigMappings;
final Set<ConfigClassWithPrefix> runtimeConfigMappings;
/**
* Regular converters organized by type. Each converter is stored in a separate field. Some are used
* only at build time, some only at run time, and some at both times.
Expand Down Expand Up @@ -343,6 +348,8 @@ public static final class GenerateOperation implements AutoCloseable {
runtimeConfigSources = builder.getRuntimeConfigSources();
runtimeConfigSourceProviders = builder.getRuntimeConfigSourceProviders();
runtimeConfigSourceFactories = builder.getRuntimeConfigSourceFactories();
staticConfigMappings = builder.getStaticConfigMappings();
runtimeConfigMappings = builder.getRuntimeConfigMappings();
cc = ClassCreator.builder().classOutput(classOutput).className(CONFIG_CLASS_NAME).setFinal(true).build();
generateEmptyParsers(cc);
// not instantiable
Expand Down Expand Up @@ -430,6 +437,11 @@ public static final class GenerateOperation implements AutoCloseable {
clinit.invokeStaticMethod(CU_ADD_SOURCE_FACTORY_PROVIDER, buildTimeBuilder,
clinit.newInstance(RCSF_NEW, clinit.load(discoveredConfigSourceFactory)));
}
// add mappings
for (ConfigClassWithPrefix configMapping : staticConfigMappings) {
clinit.invokeStaticMethod(CU_WITH_MAPPING, buildTimeBuilder,
clinit.load(configMapping.getKlass().getName()), clinit.load(configMapping.getPrefix()));
}

clinitConfig = clinit.checkCast(clinit.invokeVirtualMethod(SRCB_BUILD, buildTimeBuilder),
SmallRyeConfig.class);
Expand Down Expand Up @@ -670,6 +682,12 @@ public void run() {
readConfig.newInstance(RCSF_NEW, readConfig.load(discoveredConfigSourceFactory)));
}

// add mappings
for (ConfigClassWithPrefix configMapping : runtimeConfigMappings) {
readConfig.invokeStaticMethod(CU_WITH_MAPPING, runTimeBuilder,
readConfig.load(configMapping.getKlass().getName()), readConfig.load(configMapping.getPrefix()));
}

ResultHandle bootstrapConfig = null;
if (bootstrapConfigSetupNeeded()) {
bootstrapConfig = readBootstrapConfig.invokeVirtualMethod(SRCB_BUILD, bootstrapBuilder);
Expand Down Expand Up @@ -1686,6 +1704,9 @@ public static final class Builder {
private Set<String> runtimeConfigSourceProviders;
private Set<String> runtimeConfigSourceFactories;

private Set<ConfigClassWithPrefix> staticConfigMappings;
private Set<ConfigClassWithPrefix> runtimeConfigMappings;

Builder() {
}

Expand Down Expand Up @@ -1797,6 +1818,24 @@ public Builder setRuntimeConfigSourceFactories(final Set<String> runtimeConfigSo
return this;
}

Set<ConfigClassWithPrefix> getStaticConfigMappings() {
return staticConfigMappings;
}

public Builder setStaticConfigMappings(final Set<ConfigClassWithPrefix> staticConfigMappings) {
this.staticConfigMappings = staticConfigMappings;
return this;
}

Set<ConfigClassWithPrefix> getRuntimeConfigMappings() {
return runtimeConfigMappings;
}

public Builder setRuntimeConfigMappings(final Set<ConfigClassWithPrefix> runtimeConfigMappings) {
this.runtimeConfigMappings = runtimeConfigMappings;
return this;
}

public GenerateOperation build() {
return new GenerateOperation(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import static io.quarkus.deployment.steps.ConfigBuildSteps.SERVICES_PREFIX;
import static io.quarkus.deployment.util.ServiceUtil.classNamesNamedIn;
import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

import java.io.IOException;
import java.lang.reflect.Modifier;
Expand All @@ -29,6 +31,7 @@
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.AdditionalBootstrapConfigSourceProviderBuildItem;
import io.quarkus.deployment.builditem.AdditionalStaticInitConfigSourceProviderBuildItem;
import io.quarkus.deployment.builditem.ConfigClassBuildItem;
import io.quarkus.deployment.builditem.ConfigurationBuildItem;
import io.quarkus.deployment.builditem.ConfigurationTypeBuildItem;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
Expand All @@ -51,6 +54,7 @@
import io.quarkus.runtime.configuration.ConfigChangeRecorder;
import io.quarkus.runtime.configuration.ConfigurationRuntimeConfig;
import io.quarkus.runtime.configuration.RuntimeOverrideConfigSource;
import io.smallrye.config.ConfigMappings.ConfigClassWithPrefix;
import io.smallrye.config.ConfigSourceFactory;
import io.smallrye.config.PropertiesLocationConfigSourceFactory;

Expand Down Expand Up @@ -88,7 +92,8 @@ void generateConfigClass(
LiveReloadBuildItem liveReloadBuildItem,
List<AdditionalBootstrapConfigSourceProviderBuildItem> additionalBootstrapConfigSourceProviders,
List<StaticInitConfigSourceProviderBuildItem> staticInitConfigSourceProviders,
List<StaticInitConfigSourceFactoryBuildItem> staticInitConfigSourceFactories)
List<StaticInitConfigSourceFactoryBuildItem> staticInitConfigSourceFactories,
List<ConfigClassBuildItem> configClasses)
throws IOException {

if (liveReloadBuildItem.isLiveReload()) {
Expand Down Expand Up @@ -130,6 +135,8 @@ void generateConfigClass(
.setRuntimeConfigSources(discoveredConfigSources)
.setRuntimeConfigSourceProviders(discoveredConfigSourceProviders)
.setRuntimeConfigSourceFactories(discoveredConfigSourceFactories)
.setStaticConfigMappings(staticSafeConfigMappings(configClasses))
.setRuntimeConfigMappings(runtimeConfigMappings(configClasses))
.build()
.run();
}
Expand Down Expand Up @@ -247,4 +254,19 @@ private static Set<String> staticSafeServices(Set<String> services) {
}
return staticSafe;
}

private static Set<ConfigClassWithPrefix> staticSafeConfigMappings(List<ConfigClassBuildItem> configClasses) {
return configClasses.stream()
.filter(ConfigClassBuildItem::isMapping)
.filter(ConfigClassBuildItem::isStaticInitSafe)
.map(configMapping -> configClassWithPrefix(configMapping.getConfigClass(), configMapping.getPrefix()))
.collect(toSet());
}

private static Set<ConfigClassWithPrefix> runtimeConfigMappings(List<ConfigClassBuildItem> configClasses) {
return configClasses.stream()
.filter(ConfigClassBuildItem::isMapping)
.map(configMapping -> configClassWithPrefix(configMapping.getConfigClass(), configMapping.getPrefix()))
.collect(toSet());
}
}
Loading

0 comments on commit e3d45af

Please sign in to comment.