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

Priority of REST Client Config changed to Quarkus FQN, config key, simple name #45044

Merged
merged 1 commit into from
Dec 11, 2024
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.
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 @@ -2,11 +2,14 @@

import static io.smallrye.config.ConfigValue.CONFIG_SOURCE_COMPARATOR;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.function.Function;
import java.util.function.Supplier;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

Expand All @@ -17,7 +20,6 @@
import io.smallrye.config.ConfigValue;
import io.smallrye.config.FallbackConfigSourceInterceptor;
import io.smallrye.config.Priorities;
import io.smallrye.config.RelocateConfigSourceInterceptor;
import io.smallrye.config.SmallRyeConfigBuilder;

/**
Expand Down Expand Up @@ -70,49 +72,66 @@ public SmallRyeConfigBuilder configBuilder(final SmallRyeConfigBuilder builder)

Map<String, String> quarkusFallbacks = new HashMap<>();
Map<String, String> microProfileFallbacks = new HashMap<>();
// relocates [All Combinations] -> quarkus.rest-client."FQN".*
Map<String, String> relocates = new HashMap<>();
Map<String, List<String>> relocates = new HashMap<>();

for (RegisteredRestClient restClient : restClients) {
if (runtime) {
RestClientsConfig.RestClientKeysProvider.KEYS.add(restClient.getFullName());
}

// FQN -> Simple Name
String quotedFullName = "\"" + restClient.getFullName() + "\"";
quarkusFallbacks.put(quotedFullName, restClient.getSimpleName());
relocates.put(restClient.getSimpleName(), quotedFullName);
// Simple Name -> Quoted Simple Name
String quotedSimpleName = "\"" + restClient.getSimpleName() + "\"";
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
relocates.put(quotedSimpleName, quotedFullName);

String configKey = restClient.getConfigKey();

// relocates [All Combinations] -> quarkus.rest-client."FQN".*
List<String> fullNameRelocates = new ArrayList<>();
relocates.put(quotedFullName, fullNameRelocates);

if (configKey != null && !restClient.isConfigKeyEqualsNames()) {
String quotedConfigKey = "\"" + configKey + "\"";
if (!quotedConfigKey.equals(quotedFullName) && !quotedConfigKey.equals(quotedSimpleName)) {
if (restClient.isConfigKeyComposed()) {
// Quoted Simple Name -> Quoted Config Key
quarkusFallbacks.put(quotedSimpleName, quotedConfigKey);
relocates.put(quotedConfigKey, quotedFullName);
// FQN -> Quoted Config Key -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, quotedConfigKey);
quarkusFallbacks.put(quotedConfigKey, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(quotedConfigKey);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
} else {
// Quoted Simple Name -> Config Key
quarkusFallbacks.put(quotedSimpleName, configKey);
relocates.put(configKey, quotedFullName);
// Config Key -> Quoted Config Key
// FQN -> Config Key -> Quoted Config Key -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, configKey);
quarkusFallbacks.put(configKey, quotedConfigKey);
relocates.put(quotedConfigKey, quotedFullName);
quarkusFallbacks.put(quotedConfigKey, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(configKey);
fullNameRelocates.add(quotedConfigKey);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
}
} else {
// FQN -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
}
} else {
// FQN -> Quoted Simple Name -> Simple Name
quarkusFallbacks.put(quotedFullName, restClient.getSimpleName());
quarkusFallbacks.put(restClient.getSimpleName(), quotedSimpleName);
fullNameRelocates.add(restClient.getSimpleName());
fullNameRelocates.add(quotedSimpleName);
}

// FQN -> FQN/mp-rest
String mpRestFullName = restClient.getFullName() + "/mp-rest/";
microProfileFallbacks.put(quotedFullName, mpRestFullName);
relocates.put(mpRestFullName, quotedFullName);
fullNameRelocates.add(mpRestFullName);
if (configKey != null && !configKey.equals(restClient.getFullName())) {
String mpConfigKey = configKey + "/mp-rest/";
microProfileFallbacks.put(mpRestFullName, mpConfigKey);
relocates.put(mpConfigKey, quotedFullName);
fullNameRelocates.add(mpConfigKey);
}
}

Expand Down Expand Up @@ -145,12 +164,7 @@ public OptionalInt getPriority() {
builder.withInterceptorFactories(new ConfigSourceInterceptorFactory() {
@Override
public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context) {
return new RelocateConfigSourceInterceptor(new Relocates(relocates)) {
@Override
public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
return context.proceed(name);
}
};
return new Relocates(relocates);
}
});
return builder;
Expand Down Expand Up @@ -298,35 +312,105 @@ public String apply(final String name) {

/**
* Relocates every possible name (Quarkus and MP) to
* <code>quarkus.rest-client."[FQN of the REST Interface]".*</code>
* <code>quarkus.rest-client."[FQN of the REST Interface]".*</code>. The same <code>configKey</code> can relocate
* to many <code>quarkus.rest-client."[FQN of the REST Interface]".*</code>.
*/
private record Relocates(Map<String, String> names) implements Function<String, String> {
private static class Relocates implements ConfigSourceInterceptor {
private final Map<String, List<String>> relocates;

Relocates(final Map<String, List<String>> relocates) {
this.relocates = new HashMap<>();
// Inverts the Map to make it easier to search
for (Map.Entry<String, List<String>> entry : relocates.entrySet()) {
for (String from : entry.getValue()) {
this.relocates.putIfAbsent(from, new ArrayList<>());
this.relocates.get(from).add(entry.getKey());
}
}
}

@Override
public String apply(final String name) {
int indexOfRestClient = indexOfRestClient(name);
if (indexOfRestClient != -1) {
for (Map.Entry<String, String> entry : names.entrySet()) {
String original = entry.getKey();
String target = entry.getValue();
int endOfConfigKey = indexOfRestClient + original.length();
if (name.regionMatches(indexOfRestClient, original, 0, original.length())) {
if (name.length() > endOfConfigKey && name.charAt(endOfConfigKey) == '.') {
return REST_CLIENT_PREFIX + target + name.substring(endOfConfigKey);
public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) {
return context.proceed(name);
}

@Override
public Iterator<String> iterateNames(final ConfigSourceInterceptorContext context) {
List<String> relocatedNames = new ArrayList<>(relocates.size());
List<Supplier<Iterator<String>>> iterators = new ArrayList<>();
iterators.add(new Supplier<Iterator<String>>() {
@Override
public Iterator<String> get() {
Iterator<String> names = context.iterateNames();

return new Iterator<>() {
@Override
public boolean hasNext() {
return names.hasNext();
}
}

@Override
public String next() {
String name = names.next();
int indexOfRestClient = indexOfRestClient(name);
if (indexOfRestClient != -1) {
for (Map.Entry<String, List<String>> entry : relocates.entrySet()) {
String original = entry.getKey();
int endOfConfigKey = indexOfRestClient + original.length();
if (name.regionMatches(indexOfRestClient, original, 0, original.length())) {
if (name.length() > endOfConfigKey && name.charAt(endOfConfigKey) == '.') {
for (String relocatedName : entry.getValue()) {
relocatedNames.add(
REST_CLIENT_PREFIX + relocatedName + name.substring(endOfConfigKey));
}
return name;
}
}
}
}
int slash = name.indexOf("/");
if (slash != -1) {
if (name.regionMatches(slash + 1, "mp-rest/", 0, 8)) {
String property = name.substring(slash + 9);
if (MICROPROFILE_NAMES.containsKey(property)) {
relocatedNames.add(REST_CLIENT_PREFIX + "\"" + name.substring(0, slash) + "\"."
+ MICROPROFILE_NAMES.getOrDefault(property, property));
}
return name;
}
}
return name;
}
};
}
}
int slash = name.indexOf("/");
if (slash != -1) {
if (name.regionMatches(slash + 1, "mp-rest/", 0, 8)) {
String property = name.substring(slash + 9);
if (MICROPROFILE_NAMES.containsKey(property)) {
return REST_CLIENT_PREFIX + "\"" + name.substring(0, slash) + "\"."
+ MICROPROFILE_NAMES.getOrDefault(property, property);
});
iterators.add(new Supplier<Iterator<String>>() {
@Override
public Iterator<String> get() {
return relocatedNames.iterator();
}
});
Iterator<Supplier<Iterator<String>>> iterator = iterators.iterator();
return new Iterator<>() {
Iterator<String> names = iterator.next().get();

@Override
public boolean hasNext() {
if (names.hasNext()) {
return true;
} else {
if (iterator.hasNext()) {
names = iterator.next().get();
}
return names.hasNext();
}
}
}
return name;

@Override
public String next() {
return names.next();
}
};
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import org.junit.jupiter.api.Test;

import io.quarkus.restclient.config.RestClientsConfig.RestClientConfig;
import io.quarkus.restclient.config.key.SharedOneConfigKeyRestClient;
import io.quarkus.restclient.config.key.SharedThreeConfigKeyRestClient;
import io.quarkus.restclient.config.key.SharedTwoConfigKeyRestClient;
import io.quarkus.runtime.configuration.ConfigUtils;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;
Expand Down Expand Up @@ -233,6 +236,81 @@ public List<RegisteredRestClient> getRestClients() {
assertThat(restClientConfig.uri().get()).isEqualTo("http://localhost:8082");
}

@Test
void restClientDuplicateSimpleName() {
SmallRyeConfig config = ConfigUtils.emptyConfigBuilder()
.withMapping(RestClientsConfig.class)
.withCustomizers(new SmallRyeConfigBuilderCustomizer() {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
new AbstractRestClientConfigBuilder() {
@Override
public List<RegisteredRestClient> getRestClients() {
return List.of(
new RegisteredRestClient(
io.quarkus.restclient.config.simple.one.SimpleNameRestClient.class, "one"),
new RegisteredRestClient(
io.quarkus.restclient.config.simple.two.SimpleNameRestClient.class, "two"));
}
}.configBuilder(builder);
}
})
.build();
assertNotNull(config);

RestClientsConfig restClientsConfig = config.getConfigMapping(RestClientsConfig.class);
assertEquals(2, restClientsConfig.clients().size());
assertThat(restClientsConfig.getClient(io.quarkus.restclient.config.simple.one.SimpleNameRestClient.class).uri().get())
.isEqualTo("http://localhost:8081");
assertThat(restClientsConfig.getClient(io.quarkus.restclient.config.simple.two.SimpleNameRestClient.class).uri().get())
.isEqualTo("http://localhost:8082");
}

@Test
void restClientSharedConfigKey() {
SmallRyeConfig config = ConfigUtils.emptyConfigBuilder()
.withMapping(RestClientsConfig.class)
.withCustomizers(new SmallRyeConfigBuilderCustomizer() {
@Override
public void configBuilder(final SmallRyeConfigBuilder builder) {
new AbstractRestClientConfigBuilder() {
@Override
public List<RegisteredRestClient> getRestClients() {
return List.of(
new RegisteredRestClient(SharedOneConfigKeyRestClient.class, "shared"),
new RegisteredRestClient(SharedTwoConfigKeyRestClient.class, "shared"),
new RegisteredRestClient(SharedThreeConfigKeyRestClient.class, "shared"));
}
}.configBuilder(builder);
}
})
.build();
assertNotNull(config);

RestClientsConfig restClientsConfig = config.getConfigMapping(RestClientsConfig.class);
assertEquals(3, restClientsConfig.clients().size());

RestClientConfig restClientConfigOne = restClientsConfig.getClient(SharedOneConfigKeyRestClient.class);
assertThat(restClientConfigOne.uri().get()).isEqualTo("http://localhost:8081");
assertEquals(2, restClientConfigOne.headers().size());
assertEquals("one", restClientConfigOne.headers().get("two"));
assertEquals("two", restClientConfigOne.headers().get("one"));

RestClientConfig restClientConfigTwo = restClientsConfig
.getClient(SharedTwoConfigKeyRestClient.class);
assertThat(restClientConfigTwo.uri().get()).isEqualTo("http://localhost:8082");
assertEquals(2, restClientConfigTwo.headers().size());
assertEquals("one", restClientConfigTwo.headers().get("two"));
assertEquals("two", restClientConfigTwo.headers().get("one"));

RestClientConfig restClientConfigThree = restClientsConfig
.getClient(SharedThreeConfigKeyRestClient.class);
assertThat(restClientConfigThree.uri().get()).isEqualTo("http://localhost:8083");
assertEquals(2, restClientConfigThree.headers().size());
assertEquals("one", restClientConfigThree.headers().get("two"));
assertEquals("two", restClientConfigThree.headers().get("one"));
}

@Test
void buildTimeConfig() {
SmallRyeConfig config = ConfigUtils.emptyConfigBuilder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.key;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "shared")
public interface SharedOneConfigKeyRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.key;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "shared")
public interface SharedThreeConfigKeyRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.key;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "shared")
public interface SharedTwoConfigKeyRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.simple.one;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "one")
public interface SimpleNameRestClient {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.restclient.config.simple.two;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(configKey = "two")
public interface SimpleNameRestClient {
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,12 @@ mp.key/mp-rest/proxyAddress=mp.key
mp.key/mp-rest/queryParamStyle=COMMA_SEPARATED

MPConfigKeyRestClient/mp-rest/uri=http://localhost:8082

quarkus.rest-client.one.uri=http://localhost:8081
quarkus.rest-client.two.uri=http://localhost:8082

quarkus.rest-client."io.quarkus.restclient.config.key.SharedOneConfigKeyRestClient".uri=http://localhost:8081
quarkus.rest-client."io.quarkus.restclient.config.key.SharedTwoConfigKeyRestClient".uri=http://localhost:8082
io.quarkus.restclient.config.key.SharedThreeConfigKeyRestClient/mp-rest/uri=http://localhost:8083
quarkus.rest-client.shared.headers.two=one
quarkus.rest-client.shared.headers.one=two
Loading