Skip to content

Commit

Permalink
Normalize property resolution
Browse files Browse the repository at this point in the history
This changes alters property source processing such that the lower case hyphen separated version of a property name is all that is stored thus saving memory.

This is consistent with Grails and Spring Boot. You can still define properties in camel case, however they are normalized when read from foo.barBaz into foo.bar-baz

When reading properties with @value you should always use the lower case hyphen separated form.
  • Loading branch information
graemerocher committed Apr 25, 2018
1 parent cb8a181 commit 125910b
Show file tree
Hide file tree
Showing 51 changed files with 408 additions and 185 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class Book {
@Singleton
abstract class BookService {

@Value('${dataSource.dbCreate}')
@Value('${data-source.db-create}')
String dbCreate

abstract List<Book> list()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class ValidatorFactoryProvider {
@Inject
protected Optional<ParameterNameProvider> parameterNameProvider = Optional.empty();

@Value("${hibernate.validator.ignoreXmlConfiguration:true}")
@Value("${hibernate.validator.ignore-xml-configuration:true}")
protected boolean ignoreXmlConfiguration = true;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@

import io.micronaut.context.annotation.EachProperty;
import io.micronaut.context.annotation.Parameter;
import io.micronaut.core.convert.format.KeyFormat;
import io.micronaut.core.naming.conventions.StringConvention;
import io.micronaut.jdbc.BasicJdbcConfiguration;
import io.micronaut.jdbc.CalculatedSettings;
import org.apache.tomcat.jdbc.pool.PoolProperties;

import javax.annotation.PostConstruct;
import java.util.Properties;

/**
* Allows the configuration of Tomcat JDBC data sources. All properties on
Expand Down Expand Up @@ -63,6 +66,11 @@ void postConstruct() {
getValidationQuery();
}

@Override
public void setDbProperties(@KeyFormat(StringConvention.UNDER_SCORE_SEPARATED) Properties dbProperties) {
super.setDbProperties(dbProperties);
}

/**
* @return The calculated driver class name
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ class MongoReactiveConfigurationSpec extends Specification {
("mongodb.servers.myServer.connectionPool.${property}".toString()): value
)

NamedReactiveMongoConfiguration configuration = context.getBean(NamedReactiveMongoConfiguration, Qualifiers.byName('myServer'))
NamedReactiveMongoConfiguration configuration = context.getBean(NamedReactiveMongoConfiguration, Qualifiers.byName('my-server'))
MongoClientSettings clientSettings = configuration.buildSettings()
MongoClient mongoClient = context.getBean(MongoClient, Qualifiers.byName('myServer'))
MongoClient mongoClient = context.getBean(MongoClient, Qualifiers.byName('my-server'))

expect:
mongoClient != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.micronaut.configurations.archaius1;

import io.micronaut.core.naming.NameUtils;
import org.apache.commons.configuration.AbstractConfiguration;
import io.micronaut.context.env.Environment;
import io.micronaut.context.env.PropertySource;
Expand Down Expand Up @@ -64,12 +65,12 @@ public boolean isEmpty() {

@Override
public boolean containsKey(String key) {
return environment.containsProperty(key);
return environment.containsProperty(NameUtils.hyphenate(key));
}

@Override
public Object getProperty(String key) {
return environment.getProperty(key, Object.class).orElse(null);
return environment.getProperty(NameUtils.hyphenate(key), Object.class).orElse(null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.netflix.client.config.IClientConfigKey;
import io.micronaut.context.env.Environment;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.naming.NameUtils;
import io.micronaut.core.reflect.InstantiationUtils;
import io.micronaut.core.type.Argument;

Expand Down Expand Up @@ -241,7 +242,8 @@ protected <T> T get(IClientConfigKey<T> key, Class<T> type, T defaultValue) {
* @return concatenated result
*/
protected String qualifyKey(IClientConfigKey key) {
return getNameSpace() + "." + key.key();
String property = NameUtils.hyphenate(key.key());
return getNameSpace() + "." + property;
}

private VipAddressResolver getVipAddressResolver() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.micronaut.configurations.ribbon.RibbonLoadBalancer;
import io.micronaut.context.BeanContext;
import io.micronaut.context.annotation.Replaces;
import io.micronaut.core.naming.NameUtils;
import io.micronaut.discovery.DiscoveryClient;
import io.micronaut.http.client.LoadBalancer;
import io.micronaut.http.client.loadbalance.DiscoveryClientLoadBalancerFactory;
Expand Down Expand Up @@ -63,12 +64,14 @@ public RibbonDiscoveryClientLoadBalancerFactory(DiscoveryClient discoveryClient,

@Override
public LoadBalancer create(String serviceID) {
serviceID = NameUtils.hyphenate(serviceID);
IClientConfig niwsClientConfig = beanContext.findBean(IClientConfig.class, Qualifiers.byName(serviceID)).orElse(defaultClientConfig);
IRule rule = beanContext.findBean(IRule.class, Qualifiers.byName(serviceID)).orElseGet(() -> beanContext.createBean(IRule.class));
IPing ping = beanContext.findBean(IPing.class, Qualifiers.byName(serviceID)).orElseGet(() -> beanContext.createBean(IPing.class));
ServerListFilter serverListFilter = beanContext.findBean(ServerListFilter.class, Qualifiers.byName(serviceID)).orElseGet(() -> beanContext.createBean(ServerListFilter.class));

ServerList<Server> serverList = beanContext.findBean(ServerList.class, Qualifiers.byName(serviceID)).orElseGet(() -> new DiscoveryClientServerList(getDiscoveryClient(), serviceID));
String finalServiceID = serviceID;
ServerList<Server> serverList = beanContext.findBean(ServerList.class, Qualifiers.byName(serviceID)).orElseGet(() -> new DiscoveryClientServerList(getDiscoveryClient(), finalServiceID));

if (niwsClientConfig.getPropertyAsBoolean(CommonClientConfigKey.InitializeNFLoadBalancer, true)) {
return createRibbonLoadBalancer(niwsClientConfig, rule, ping, serverListFilter, serverList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ protected void registerDefaultConverters() {
return Optional.of(val);
} catch (IllegalArgumentException e) {
try {
Enum val = Enum.valueOf(targetType, NameUtils.underscoreSeparate(stringValue).toUpperCase(Locale.ENGLISH));
Enum val = Enum.valueOf(targetType, NameUtils.environmentName(stringValue));
return Optional.of(val);
} catch (Exception e1) {
context.reject(object, e);
Expand Down
37 changes: 37 additions & 0 deletions core/src/main/java/io/micronaut/core/convert/format/KeyFormat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2018 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.core.convert.format;
import io.micronaut.core.naming.conventions.StringConvention;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

/**
* Allows configuring the format of Map keys.
*
* @author Graeme Rocher
* @since 1.0
*/
@Documented
@Retention(RUNTIME)
public @interface KeyFormat {
/**
* @return The string conversion to use
*/
StringConvention value();
}
56 changes: 51 additions & 5 deletions core/src/main/java/io/micronaut/core/naming/NameUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public static String hyphenate(String name) {
*/
public static String hyphenate(String name, boolean lowerCase) {
char separatorChar = '-';
return separateCamelCase(name, lowerCase, separatorChar);
return separateCamelCase(name.replace('_','-'), lowerCase, separatorChar);
}

/**
Expand Down Expand Up @@ -140,6 +140,17 @@ public static String underscoreSeparate(String camelCase) {
return separateCamelCase(camelCase, false, '_');
}

/**
* Returns the underscore separated version of the given camel case string.
*
* @param camelCase The camel case name
* @return The underscore separated version
*/
public static String environmentName(String camelCase) {
return separateCamelCase(camelCase.replace('-', '_').replace('.', '_'), false, '_')
.toUpperCase(Locale.ENGLISH);
}

/**
* Returns the simple name for a class represented as string.
*
Expand Down Expand Up @@ -222,12 +233,20 @@ private static String separateCamelCase(String name, boolean lowerCase, char sep
first = false;
} else {
if (Character.isUpperCase(c) && !Character.isUpperCase(last)) {
newName.append(separatorChar).append(c);
if(c != separatorChar) {
newName.append(separatorChar);
}
newName.append(c);
} else {
if (c == '.') {
first = true;
}
newName.append(c);
if(c != separatorChar) {
if(last == separatorChar) {
newName.append(separatorChar);
}
newName.append(c);
}
}
}
last = c;
Expand All @@ -239,10 +258,14 @@ private static String separateCamelCase(String name, boolean lowerCase, char sep
boolean first = true;
char last = '0';
for (char c : chars) {

if (Character.isLowerCase(c) || !Character.isLetter(c)) {
first = false;
newName.append(c);
if(c != separatorChar) {
if(last == separatorChar) {
newName.append(separatorChar);
}
newName.append(c);
}
} else {
char lowerCaseChar = Character.toLowerCase(c);
if (first) {
Expand Down Expand Up @@ -281,4 +304,27 @@ public static String extension(String filename) {
return filename.substring(index + 1);
}
}

/**
* The camel case version of the string with the first letter in lower case
* @param str The string
* @return The new string in camel case
*/
public static String camelCase(String str) {
return camelCase(str, true);
}

/**
* The camel case version of the string with the first letter in lower case
* @param str The string
* @param lowerCaseFirstLetter Whether the first letter is in upper case or lower case
* @return The new string in camel case
*/
public static String camelCase(String str, boolean lowerCaseFirstLetter) {
String result = Arrays.stream(str.split("[\\s_-]")).map(NameUtils::capitalize).collect(Collectors.joining(""));
if(lowerCaseFirstLetter) {
return decapitalize(result);
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2018 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.core.naming.conventions;

import io.micronaut.core.naming.NameUtils;

/**
* An enum representing different conventions for
*
* @author graemerocher
* @since 1.0
*/
public enum StringConvention {
/**
* Camel case capitalized like class names
*
* Example: FooBar
*/
CAMEL_CASE_CAPITALIZED,
/**
* Camel case, lower case first letter
*
* Example: fooBar
*/
CAMEL_CASE,

/**
* Hyphenated, in lower case. Example foo-bar
*/
HYPHENATED,

/**
* Hyphenated, in upper case. Example FOO_BAR
*/
UNDER_SCORE_SEPARATED;

/**
* Format the string with this format
*
* @param str The string
* @return The formatted string
*/
public String format(String str) {
return StringConvention.format(this, str);
}

public static String format(StringConvention convention, String str) {
switch (convention) {
case CAMEL_CASE:
return NameUtils.camelCase(str);
case HYPHENATED:
return NameUtils.hyphenate(str);
case UNDER_SCORE_SEPARATED:
return NameUtils.environmentName(str);
case CAMEL_CASE_CAPITALIZED:
default:
return NameUtils.camelCase(str, false);
}
}
}
2 changes: 2 additions & 0 deletions core/src/main/java/io/micronaut/core/util/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public static boolean hasText(@Nullable CharSequence str) {
* @param objects The objects
* @return An set of strings
*/
@SuppressWarnings("unused")
public static Set<String> internSetOf(Object... objects) {
if (objects == null || objects.length == 0) {
return Collections.emptySet();
Expand All @@ -104,6 +105,7 @@ public static Set<String> internSetOf(Object... objects) {
* @return An unmodifiable set of strings
* @see CollectionUtils#mapOf(Object...)
*/
@SuppressWarnings("unused")
public static Map<String, Object> internMapOf(Object... values) {
if (values == null) {
return Collections.emptyMap();
Expand Down
Loading

0 comments on commit 125910b

Please sign in to comment.