Skip to content

Commit

Permalink
Move REST Client configuration to use @ConfigMapping
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Jul 25, 2024
1 parent ec8e234 commit 4f31e0d
Show file tree
Hide file tree
Showing 34 changed files with 1,276 additions and 1,304 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 4f31e0d

Please sign in to comment.