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

Register implicit Converters for ConfigProperties #15053

Merged
merged 1 commit into from
Feb 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ private String getPropertyName(String name, ClassInfo declaringClass) {
return builder.append(".").append(name).toString();
}

private boolean isHandledByProducers(Type type) {
public static boolean isHandledByProducers(Type type) {
if (type.kind() == Kind.ARRAY) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.createReadMandatoryValueAndConvertIfNeeded;
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.createReadOptionalValueAndConvertIfNeeded;
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.determineSingleGenericType;
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.registerImplicitConverter;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
Expand Down Expand Up @@ -38,6 +39,7 @@
import io.quarkus.deployment.Capability;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.bean.JavaBeanUtil;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem;
import io.quarkus.gizmo.BranchResult;
import io.quarkus.gizmo.BytecodeCreator;
Expand All @@ -63,18 +65,22 @@ final class ClassConfigPropertiesUtil {
private final YamlListObjectHandler yamlListObjectHandler;
private final ClassCreator producerClassCreator;
private final Capabilities capabilities;
private final BuildProducer<ReflectiveClassBuildItem> reflectiveClasses;
private final BuildProducer<ReflectiveMethodBuildItem> reflectiveMethods;
private final BuildProducer<ConfigPropertyBuildItem> configProperties;

ClassConfigPropertiesUtil(IndexView applicationIndex, YamlListObjectHandler yamlListObjectHandler,
ClassCreator producerClassCreator,
Capabilities capabilities, BuildProducer<ReflectiveMethodBuildItem> reflectiveMethods,
Capabilities capabilities,
BuildProducer<ReflectiveClassBuildItem> reflectiveClasses,
BuildProducer<ReflectiveMethodBuildItem> reflectiveMethods,
BuildProducer<ConfigPropertyBuildItem> configProperties) {

this.applicationIndex = applicationIndex;
this.yamlListObjectHandler = yamlListObjectHandler;
this.producerClassCreator = producerClassCreator;
this.capabilities = capabilities;
this.reflectiveClasses = reflectiveClasses;
this.reflectiveMethods = reflectiveMethods;
this.configProperties = configProperties;
}
Expand Down Expand Up @@ -341,6 +347,7 @@ private ResultHandle populateConfigObject(ClassLoader classLoader, ClassInfo con

// config.getOptionalValue
if (genericType.kind() != Type.Kind.PARAMETERIZED_TYPE) {
registerImplicitConverter(genericType, reflectiveClasses);
ResultHandle setterValue = methodCreator.invokeInterfaceMethod(
MethodDescriptor.ofMethod(Config.class, "getOptionalValue", Optional.class, String.class,
Class.class),
Expand Down Expand Up @@ -375,6 +382,7 @@ private ResultHandle populateConfigObject(ClassLoader classLoader, ClassInfo con
getEffectiveConfigName(namingStrategy, field), fullConfigName);
createWriteValue(methodCreator, configObject, field, setter, useFieldAccess, setterValue);
} else {
registerImplicitConverter(fieldType, reflectiveClasses);
populateTypicalProperty(methodCreator, configObject, configPropertyBuildItemCandidates,
currentClassInHierarchy, field, useFieldAccess, fieldType, setter, mpConfig,
fullConfigName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,11 @@ void setup(CombinedIndexBuildItem combinedIndex,
IndexView index = combinedIndex.getIndex();
YamlListObjectHandler yamlListObjectHandler = new YamlListObjectHandler(nonBeansClassOutput, index, reflectiveClasses);
ClassConfigPropertiesUtil classConfigPropertiesUtil = new ClassConfigPropertiesUtil(index,
yamlListObjectHandler, producerClassCreator, capabilities, reflectiveMethods, configProperties);
yamlListObjectHandler, producerClassCreator, capabilities, reflectiveClasses, reflectiveMethods,
configProperties);
InterfaceConfigPropertiesUtil interfaceConfigPropertiesUtil = new InterfaceConfigPropertiesUtil(index,
yamlListObjectHandler, nonBeansClassOutput, producerClassCreator, capabilities, defaultConfigValues,
configProperties);
configProperties, reflectiveClasses);
for (ConfigPropertiesMetadataBuildItem configPropertiesMetadata : configPropertiesMetadataList) {
ClassInfo classInfo = configPropertiesMetadata.getClassInfo();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import org.jboss.jandex.ParameterizedType;
import org.jboss.jandex.Type;

import io.quarkus.arc.deployment.ConfigBuildStep;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.gizmo.BranchResult;
import io.quarkus.gizmo.BytecodeCreator;
import io.quarkus.gizmo.MethodDescriptor;
Expand Down Expand Up @@ -142,6 +145,15 @@ static Type determineSingleGenericType(Type type, DotName declaringClass) {
return type.asParameterizedType().arguments().get(0);
}

static void registerImplicitConverter(Type type, BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) {
// We need to register for reflection in case an implicit converter is required.
if (!ConfigBuildStep.isHandledByProducers(type)) {
if (type.kind() != Type.Kind.ARRAY) {
reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, type.name().toString()));
}
}
}

static class ReadOptionalResponse {
private final ResultHandle value; //this is only valid within 'isPresentTrue'
private final BytecodeCreator isPresentTrue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.createReadMandatoryValueAndConvertIfNeeded;
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.createReadOptionalValueAndConvertIfNeeded;
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.determineSingleGenericType;
import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.registerImplicitConverter;
import static io.quarkus.gizmo.MethodDescriptor.ofMethod;

import java.lang.annotation.Annotation;
Expand Down Expand Up @@ -38,6 +39,7 @@
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.bean.JavaBeanUtil;
import io.quarkus.deployment.builditem.RunTimeConfigurationDefaultBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.gizmo.FieldDescriptor;
Expand All @@ -55,18 +57,21 @@ final class InterfaceConfigPropertiesUtil {
private final Capabilities capabilities;
private final BuildProducer<RunTimeConfigurationDefaultBuildItem> defaultConfigValues;
private final BuildProducer<ConfigPropertyBuildItem> configProperties;
private final BuildProducer<ReflectiveClassBuildItem> reflectiveClasses;

InterfaceConfigPropertiesUtil(IndexView index, YamlListObjectHandler yamlListObjectHandler, ClassOutput classOutput,
ClassCreator classCreator,
Capabilities capabilities, BuildProducer<RunTimeConfigurationDefaultBuildItem> defaultConfigValues,
BuildProducer<ConfigPropertyBuildItem> configProperties) {
BuildProducer<ConfigPropertyBuildItem> configProperties,
BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) {
this.index = index;
this.yamlListObjectHandler = yamlListObjectHandler;
this.classOutput = classOutput;
this.classCreator = classCreator;
this.capabilities = capabilities;
this.defaultConfigValues = defaultConfigValues;
this.configProperties = configProperties;
this.reflectiveClasses = reflectiveClasses;
}

/**
Expand Down Expand Up @@ -216,6 +221,7 @@ private String generateImplementationForInterfaceConfigPropertiesRec(ClassInfo o
method.declaringClass().name());

if (genericType.kind() != Type.Kind.PARAMETERIZED_TYPE) {
registerImplicitConverter(genericType, reflectiveClasses);
ResultHandle result = methodCreator.invokeInterfaceMethod(
MethodDescriptor.ofMethod(Config.class, "getOptionalValue", Optional.class,
String.class,
Expand Down Expand Up @@ -262,6 +268,7 @@ private String generateImplementationForInterfaceConfigPropertiesRec(ClassInfo o
.produce(new RunTimeConfigurationDefaultBuildItem(fullConfigName, defaultValueStr));
}
// use config.getValue to obtain and return the result taking converting it to collection if needed
registerImplicitConverter(returnType, reflectiveClasses);
ResultHandle value = createReadMandatoryValueAndConvertIfNeeded(
fullConfigName, returnType,
method.declaringClass().name(), methodCreator, config);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package io.quarkus.it.config;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.Optional;

import javax.validation.constraints.Size;
import javax.ws.rs.GET;
Expand All @@ -12,27 +17,46 @@
public class ConfigPropertiesResource {

final GreetingConfiguration greetingConfiguration;
final GreetingConfigurationI greetingConfigurationI;

public ConfigPropertiesResource(GreetingConfiguration greetingConfiguration) {
public ConfigPropertiesResource(GreetingConfiguration greetingConfiguration,
GreetingConfigurationI greetingConfigurationI) {
this.greetingConfiguration = greetingConfiguration;
this.greetingConfigurationI = greetingConfigurationI;
}

@GET
public String greet() {
return greetingConfiguration.message + greetingConfiguration.number + greetingConfiguration.suffix;
}

@GET
@Path("/period")
public String period() {
return greetingConfiguration.period.get().toString();
}

@ConfigProperties(prefix = "configproperties")
public static class GreetingConfiguration {
@Size(min = 2)
public String message;
public String suffix = "!";
public BigDecimal other;
public NumberEnum number;
// Force to use implicit converter to check for reflective registration
public LocalDate date;
public Optional<Period> period;
}

public enum NumberEnum {
ONE,
TWO;
}

@ConfigProperties(prefix = "configproperties")
public interface GreetingConfigurationI {
LocalDateTime dateTime();

Optional<Instant> instant();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ microprofile.cidr-address=10.0.0.20/24
configproperties.message=Hello
configproperties.other=1
configproperties.number=ONE
configproperties.date=2020-10-10
configproperties.date-time=2020-10-10T10:10
configproperties.period=P1D
configproperties.instant=2010-10-10T10:10:10Z

quarkus.swagger-ui.always-include=true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,11 @@ public void testConfigPropertiesProperlyInjected() {
.when().get("/configuration-properties")
.then().body(is("HelloONE!"));
}

@Test
public void testImplicitConverters() {
RestAssured
.when().get("/configuration-properties/period")
.then().body(is("P1D"));
}
}