Skip to content

Commit

Permalink
Generate defaults and properties for all super types (#1073)
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez authored Dec 24, 2023
1 parent 88e86f4 commit c9f2a66
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ protected ConfigMappingInterface computeValue(final Class<?> type) {
private final String className;
private final ConfigMappingInterface[] superTypes;
private final Property[] properties;
private final Map<String, Property> propertiesByName;
private final ToStringMethod toStringMethod;

ConfigMappingInterface(final Class<?> interfaceType, final ConfigMappingInterface[] superTypes,
Expand All @@ -50,12 +49,10 @@ protected ConfigMappingInterface computeValue(final Class<?> type) {
this.superTypes = superTypes;

List<Property> filteredProperties = new ArrayList<>();
Map<String, Property> propertiesByName = new HashMap<>();
ToStringMethod toStringMethod = null;
for (Property property : properties) {
if (!property.isToStringMethod()) {
filteredProperties.add(property);
propertiesByName.put(property.getMethod().getName(), property);
} else {
toStringMethod = (ToStringMethod) property;
}
Expand All @@ -65,7 +62,6 @@ protected ConfigMappingInterface computeValue(final Class<?> type) {
}

this.properties = filteredProperties.toArray(new Property[0]);
this.propertiesByName = propertiesByName;
this.toStringMethod = toStringMethod;
}

Expand All @@ -89,64 +85,29 @@ public Class<?> getInterfaceType() {
return interfaceType;
}

/**
* Get the number of supertypes which define configuration properties. Implemented interfaces which do not
* define any configuration properties and whose supertypes in turn do not define any configuration properties
* are not counted.
*
* @return the number of supertypes
*/
int getSuperTypeCount() {
return superTypes.length;
}

public ConfigMappingInterface[] getSuperTypes() {
return superTypes;
}

/**
* Get the supertype at the given index, which must be greater than or equal to zero and less than the value returned
* by {@link #getSuperTypeCount()}.
*
* @param index the index
* @return the supertype definition
* @throws IndexOutOfBoundsException if {@code index} is invalid
*/
ConfigMappingInterface getSuperType(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= superTypes.length)
throw new IndexOutOfBoundsException();
return superTypes[index];
}

public Property[] getProperties() {
return properties;
}

/**
* Get the number of properties defined on this type (excluding supertypes).
*
* @return the number of properties
*/
int getPropertyCount() {
return properties.length;
}

/**
* Get the property definition at the given index, which must be greater than or equal to zero and less than the
* value returned by {@link #getPropertyCount()}.
*
* @param index the index
* @return the property definition
* @throws IndexOutOfBoundsException if {@code index} is invalid
*/
Property getProperty(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= properties.length)
throw new IndexOutOfBoundsException();
return properties[index];
}

Property getProperty(final String name) {
return propertiesByName.get(name);
public Property[] getProperties(boolean includeSuper) {
if (includeSuper) {
Map<String, Property> properties = new HashMap<>();
for (ConfigMappingInterface superType : superTypes) {
for (Property property : superType.getProperties()) {
properties.put(property.getMethod().getName(), property);
}
}
for (Property property : getProperties()) {
properties.put(property.getMethod().getName(), property);
}
return properties.values().toArray(new Property[0]);
} else {
return getProperties();
}
}

public boolean hasNamingStrategy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ public String apply(final String path) {
}
};
ConfigMappingInterface configMapping = ConfigMappingLoader.getConfigMapping(configClass.getKlass());
for (ConfigMappingInterface superType : configMapping.getSuperTypes()) {
getProperties(new GroupProperty(null, null, superType), configMapping.getNamingStrategy(), path, properties);
}
getProperties(new GroupProperty(null, null, configMapping), configMapping.getNamingStrategy(), path, properties);
return properties;
}
Expand All @@ -73,30 +70,7 @@ public static Set<String> getKeys(final ConfigClassWithPrefix configClass) {
}

public static Map<String, String> getDefaults(final ConfigClassWithPrefix configClass) {
Function<String, String> path = new Function<>() {
@Override
public String apply(final String path) {
return configClass.getPrefix().isEmpty() && !path.isEmpty() ? path.substring(1)
: configClass.getPrefix() + path;
}
};
ConfigMappingInterface configMapping = ConfigMappingLoader.getConfigMapping(configClass.getKlass());
Map<String, String> defaults = new HashMap<>();

for (ConfigMappingInterface superType : configMapping.getSuperTypes()) {
Map<Class<?>, Map<String, Map<String, Property>>> properties = new HashMap<>();
getProperties(new GroupProperty(null, null, superType), configMapping.getNamingStrategy(), path, properties);
for (Map.Entry<Class<?>, Map<String, Map<String, Property>>> mappingEntry : properties.entrySet()) {
for (Map.Entry<String, Map<String, Property>> prefixEntry : mappingEntry.getValue().entrySet()) {
for (Map.Entry<String, Property> propertyEntry : prefixEntry.getValue().entrySet()) {
if (propertyEntry.getValue().hasDefaultValue()) {
defaults.put(propertyEntry.getKey(), propertyEntry.getValue().getDefaultValue());
}
}
}
}
}

Map<Class<?>, Map<String, Map<String, Property>>> properties = getProperties(configClass);
for (Map.Entry<String, Property> entry : properties.get(configClass.getKlass()).get(configClass.getPrefix())
.entrySet()) {
Expand Down Expand Up @@ -154,7 +128,7 @@ private static void getProperties(
final Map<Class<?>, Map<String, Map<String, Property>>> properties,
final Map<String, Property> groupProperties) {

for (Property property : groupProperty.getGroupType().getProperties()) {
for (Property property : groupProperty.getGroupType().getProperties(true)) {
getProperty(property, namingStrategy, path, properties, groupProperties);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.smallrye.config;

import static io.smallrye.config.ConfigMappingDefaultsTest.S3BuildTimeConfig.AsyncHttpClientBuildTimeConfig.AsyncClientType.NETTY;
import static io.smallrye.config.ConfigMappingDefaultsTest.S3BuildTimeConfig.SyncHttpClientBuildTimeConfig.SyncClientType.URL;
import static io.smallrye.config.ConfigMappings.getDefaults;
import static io.smallrye.config.ConfigMappings.ConfigClassWithPrefix.configClassWithPrefix;
import static io.smallrye.config.KeyValuesConfigSource.config;
Expand All @@ -13,6 +15,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;

import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -601,4 +604,73 @@ interface MapDefaults {
@WithDefault("foo,bar")
Map<String, List<String>> map();
}

@Test
void groupParentDefaults() {
SmallRyeConfig config = new SmallRyeConfigBuilder()
.withMapping(S3BuildTimeConfig.class)
.build();

S3BuildTimeConfig mapping = config.getConfigMapping(S3BuildTimeConfig.class);
assertEquals(URL, mapping.syncClient().type());
assertEquals(NETTY, mapping.asyncClient().type());
assertIterableEquals(Set.of("default"), mapping.devservices().buckets());
assertFalse(mapping.devservices().shared());
assertEquals("localstack", mapping.devservices().serviceName());
}

@ConfigMapping(prefix = "quarkus.s3")
public interface S3BuildTimeConfig extends HasSdkBuildTimeConfig {
SyncHttpClientBuildTimeConfig syncClient();

AsyncHttpClientBuildTimeConfig asyncClient();

S3DevServicesBuildTimeConfig devservices();

interface SyncHttpClientBuildTimeConfig {
@WithDefault(value = "url")
SyncClientType type();

enum SyncClientType {
URL,
APACHE
}
}

interface AsyncHttpClientBuildTimeConfig {
@WithDefault(value = "netty")
AsyncClientType type();

enum AsyncClientType {
NETTY,
AWS_CRT
}
}

interface S3DevServicesBuildTimeConfig extends DevServicesBuildTimeConfig {
@WithDefault(value = "default")
Set<String> buckets();
}
}

public interface HasSdkBuildTimeConfig {
@WithParentName
SdkBuildTimeConfig sdk();
}

public interface SdkBuildTimeConfig {
Optional<List<String>> interceptors();
}

public interface DevServicesBuildTimeConfig {
Optional<Boolean> enabled();

@WithDefault(value = "false")
boolean shared();

@WithDefault(value = "localstack")
String serviceName();

Map<String, String> containerProperties();
}
}

0 comments on commit c9f2a66

Please sign in to comment.