Skip to content

Commit

Permalink
Merge pull request #42106 from radcortez/rest-client-config
Browse files Browse the repository at this point in the history
Move REST Client configuration to use @ConfigMapping
  • Loading branch information
gsmet authored Aug 1, 2024
2 parents ac63f53 + 044af63 commit 7f35270
Show file tree
Hide file tree
Showing 38 changed files with 1,339 additions and 1,331 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,26 @@
import static io.quarkus.restclient.config.Constants.MP_REST_SCOPE_FORMAT;
import static io.quarkus.restclient.config.Constants.QUARKUS_REST_SCOPE_FORMAT;

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

import org.eclipse.microprofile.config.Config;
import org.jboss.jandex.ClassInfo;

import io.quarkus.deployment.GeneratedClassGizmoAdaptor;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem;
import io.quarkus.deployment.builditem.StaticInitConfigBuilderBuildItem;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.restclient.config.AbstractRestClientConfigBuilder;
import io.quarkus.restclient.config.RegisteredRestClient;
import io.quarkus.runtime.configuration.ConfigBuilder;

public final class RestClientConfigUtils {

private RestClientConfigUtils() {
Expand Down Expand Up @@ -50,4 +65,40 @@ public static Optional<String> getDefaultScope(Config config) {
return config.getOptionalValue(GLOBAL_REST_SCOPE_FORMAT, String.class);
}

public static void generateRestClientConfigBuilder(
List<RegisteredRestClient> restClients,
BuildProducer<GeneratedClassBuildItem> generatedClass,
BuildProducer<StaticInitConfigBuilderBuildItem> staticInitConfigBuilder,
BuildProducer<RunTimeConfigBuilderBuildItem> runTimeConfigBuilder) {

String className = "io.quarkus.runtime.generated.RestClientConfigBuilder";
try (ClassCreator classCreator = ClassCreator.builder()
.classOutput(new GeneratedClassGizmoAdaptor(generatedClass, true))
.className(className)
.superClass(AbstractRestClientConfigBuilder.class)
.interfaces(ConfigBuilder.class)
.setFinal(true)
.build()) {

MethodCreator method = classCreator.getMethodCreator(
MethodDescriptor.ofMethod(AbstractRestClientConfigBuilder.class, "getRestClients", List.class));

ResultHandle list = method.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
for (RegisteredRestClient restClient : restClients) {
ResultHandle restClientElement = method.newInstance(
MethodDescriptor.ofConstructor(RegisteredRestClient.class, String.class, String.class, String.class),
method.load(restClient.getFullName()),
method.load(restClient.getSimpleName()),
restClient.getConfigKey() != null ? method.load(restClient.getConfigKey()) : method.loadNull());

method.invokeVirtualMethod(MethodDescriptor.ofMethod(ArrayList.class, "add", boolean.class, Object.class), list,
restClientElement);
}

method.returnValue(list);
}

staticInitConfigBuilder.produce(new StaticInitConfigBuilderBuildItem(className));
runTimeConfigBuilder.produce(new RunTimeConfigBuilderBuildItem(className));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.quarkus.restclient.config;

import java.util.List;

import io.quarkus.runtime.configuration.ConfigBuilder;
import io.smallrye.config.SmallRyeConfigBuilder;

/**
* Registers and force load REST Client configuration.
* <p>
* Usually, named configuration is mapped using a <code>Map</code> because the names are dynamic and unknown to
* Quarkus. In the case of the REST Client, configuration names are fixed and known at build time, but not to the point
* where the names can be mapped statically, so they still need to be mapped in a <code>Map</code>.
* <p>
* To populate a <code>Map</code>, because the names are dynamic, the Config system has to rely on the list of
* property names provided by each source. This also applies to the REST Client, but since the names are known to
* Quarkus, the REST Client configuration could be loaded even for sources that don't provide a list of property
* names. To achieve such behaviour, we provide a dummy configuration under each REST Client name to force
* the Config system to look up the remaining configuration in the same tree.
* <p>
* The concrete implementation is bytecode generated in
* <code>io.quarkus.restclient.config.deployment.RestClientConfigUtils#generateRestClientConfigBuilder</code>
*/
public abstract class AbstractRestClientConfigBuilder implements ConfigBuilder {
@Override
public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder) {
List<RegisteredRestClient> restClients = getRestClients();
builder.withInterceptors(new RestClientNameFallbackConfigSourceInterceptor(restClients));
for (RegisteredRestClient restClient : restClients) {
builder.withDefaultValue("quarkus.rest-client.\"" + restClient.getFullName() + "\".force", "true");
builder.withDefaultValue("quarkus.rest-client." + restClient.getSimpleName() + ".force", "true");
if (restClient.getConfigKey() != null) {
builder.withDefaultValue("quarkus.rest-client." + restClient.getConfigKey() + ".force", "true");
}
}
return builder;
}

public abstract List<RegisteredRestClient> getRestClients();
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.quarkus.restclient.config;

public class RegisteredRestClient {
private final String fullName;
private final String simpleName;
private final String configKey;

public RegisteredRestClient(final String fullName, final String simpleName) {
this(fullName, simpleName, null);
}

public RegisteredRestClient(final String fullName, final String simpleName, final String configKey) {
this.fullName = fullName;
this.simpleName = simpleName;
this.configKey = configKey;
}

public String getFullName() {
return fullName;
}

public String getSimpleName() {
return simpleName;
}

public String getConfigKey() {
return configKey;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@

import java.util.ServiceLoader;

import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.rest.client.RestClientBuilder;

import io.smallrye.config.SmallRyeConfig;

/**
* Factory which creates MicroProfile RestClientBuilder instance configured according to current Quarkus application
* configuration.
*
* <p>
* The builder instance can be further tweaked, if needed, before building the rest client proxy.
*/
public interface RestClientBuilderFactory {

default RestClientBuilder newBuilder(Class<?> proxyType) {
return newBuilder(proxyType, RestClientsConfig.getInstance());
return newBuilder(proxyType,
ConfigProvider.getConfig().unwrap(SmallRyeConfig.class).getConfigMapping(RestClientsConfig.class));
}

RestClientBuilder newBuilder(Class<?> proxyType, RestClientsConfig restClientsConfigRoot);
Expand Down
Loading

0 comments on commit 7f35270

Please sign in to comment.