From 125910b828955c78e1cfa0a5427d2561fd1636d2 Mon Sep 17 00:00:00 2001 From: graemerocher Date: Wed, 25 Apr 2018 18:04:00 +0200 Subject: [PATCH] Normalize property resolution 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. --- .../hibernate/gorm/GormConfigSpec.groovy | 2 +- .../validator/ValidatorFactoryProvider.java | 2 +- .../jdbc/tomcat/DatasourceConfiguration.java | 8 ++ .../MongoReactiveConfigurationSpec.groovy | 4 +- .../archaius1/EnvironmentConfiguration.java | 5 +- .../ribbon/AbstractRibbonClientConfig.java | 4 +- ...bonDiscoveryClientLoadBalancerFactory.java | 5 +- .../convert/DefaultConversionService.java | 2 +- .../core/convert/format/KeyFormat.java | 37 ++++++++++ .../io/micronaut/core/naming/NameUtils.java | 56 ++++++++++++-- .../naming/conventions/StringConvention.java | 73 +++++++++++++++++++ .../io/micronaut/core/util/StringUtils.java | 2 + .../core/naming/NameUtilsSpec.groovy | 54 +++++++++++--- .../Route53ClientDiscoveryConfiguration.java | 2 +- .../DiscoveryClientCacheConfiguration.java | 4 +- .../client/v1/AbstractConsulClient.java | 2 + .../discovery/eureka/EurekaConfiguration.java | 30 +++++--- .../client/v2/AbstractEurekaClient.java | 2 + .../kubernetes/KubernetesDiscoveryClient.java | 3 +- .../consul/ConsulMockHealthStatusSpec.groovy | 2 +- .../discovery/consul/MockConsulAuth.groovy | 15 +--- .../discovery/consul/TtlHeartbeatSpec.groovy | 3 +- .../EurekaMockAutoRegistrationSpec.groovy | 17 +++-- .../eureka/EurekaMockHeartbeatSpec.groovy | 14 ++-- .../discovery/eureka/MockEurekaAuth.groovy | 17 +---- .../discovery/eureka/MockEurekaServer.groovy | 20 +---- .../web/AnnotatedFunctionRouteBuilder.java | 2 +- .../client/DefaultLoadBalancerResolver.java | 2 + .../requiresproperty/package-info.groovy | 2 +- .../BeanDefinitionInjectProcessor.java | 6 +- .../ConfigPropertiesParseSpec.groovy | 4 +- ...avaConfigurationMetadataBuilderSpec.groovy | 10 +-- .../requiresproperty/package-info.java | 2 +- .../foreach/EachPropertyParseSpec.groovy | 4 +- .../context/AbstractBeanDefinition.java | 15 +++- .../DefaultPropertyPlaceholderResolver.java | 9 ++- .../env/PropertySourcePropertyResolver.java | 34 ++++----- .../ConfigurationMetadataBuilder.java | 7 +- .../PropertySourcePropertyResolverSpec.groovy | 25 ++++++- .../yaml/YamlPropertySourceLoaderSpec.groovy | 10 +-- .../health/monitor/HealthMonitorTask.java | 2 +- .../web/router/DefaultRouteBuilder.java | 2 +- .../discovery/CompositeDiscoveryClient.java | 5 +- .../discovery/config/ConfigurationClient.java | 4 +- .../io/micronaut/health/HeartbeatTask.java | 2 +- .../jackson/bind/MapToObjectConverter.java | 17 ++++- .../runtime/ApplicationConfiguration.java | 7 +- .../micronaut/jackson/JacksonSetupSpec.groovy | 8 +- .../env/JsonPropertySourceLoaderSpec.groovy | 8 +- .../core/env/PropertyResolverAdapter.java | 19 ++--- src/main/docs/guide/ioc/configurations.adoc | 2 +- 51 files changed, 408 insertions(+), 185 deletions(-) create mode 100644 core/src/main/java/io/micronaut/core/convert/format/KeyFormat.java create mode 100644 core/src/main/java/io/micronaut/core/naming/conventions/StringConvention.java diff --git a/configurations/hibernate-gorm/src/test/groovy/io/micronaut/configuration/hibernate/gorm/GormConfigSpec.groovy b/configurations/hibernate-gorm/src/test/groovy/io/micronaut/configuration/hibernate/gorm/GormConfigSpec.groovy index 4dfbfdf1d6e..5fdc498750c 100644 --- a/configurations/hibernate-gorm/src/test/groovy/io/micronaut/configuration/hibernate/gorm/GormConfigSpec.groovy +++ b/configurations/hibernate-gorm/src/test/groovy/io/micronaut/configuration/hibernate/gorm/GormConfigSpec.groovy @@ -104,7 +104,7 @@ class Book { @Singleton abstract class BookService { - @Value('${dataSource.dbCreate}') + @Value('${data-source.db-create}') String dbCreate abstract List list() diff --git a/configurations/hibernate-validator/src/main/java/io/micronaut/configuration/hibernate/validator/ValidatorFactoryProvider.java b/configurations/hibernate-validator/src/main/java/io/micronaut/configuration/hibernate/validator/ValidatorFactoryProvider.java index bfbe55edf86..f8ad8f6910c 100644 --- a/configurations/hibernate-validator/src/main/java/io/micronaut/configuration/hibernate/validator/ValidatorFactoryProvider.java +++ b/configurations/hibernate-validator/src/main/java/io/micronaut/configuration/hibernate/validator/ValidatorFactoryProvider.java @@ -55,7 +55,7 @@ public class ValidatorFactoryProvider { @Inject protected Optional parameterNameProvider = Optional.empty(); - @Value("${hibernate.validator.ignoreXmlConfiguration:true}") + @Value("${hibernate.validator.ignore-xml-configuration:true}") protected boolean ignoreXmlConfiguration = true; /** diff --git a/configurations/jdbc-tomcat/src/main/java/io/micronaut/configuration/jdbc/tomcat/DatasourceConfiguration.java b/configurations/jdbc-tomcat/src/main/java/io/micronaut/configuration/jdbc/tomcat/DatasourceConfiguration.java index e8df92f699c..ffc3db3f781 100644 --- a/configurations/jdbc-tomcat/src/main/java/io/micronaut/configuration/jdbc/tomcat/DatasourceConfiguration.java +++ b/configurations/jdbc-tomcat/src/main/java/io/micronaut/configuration/jdbc/tomcat/DatasourceConfiguration.java @@ -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 @@ -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 */ diff --git a/configurations/mongo-reactive/src/test/groovy/io/micronaut/configuration/mongo/reactive/MongoReactiveConfigurationSpec.groovy b/configurations/mongo-reactive/src/test/groovy/io/micronaut/configuration/mongo/reactive/MongoReactiveConfigurationSpec.groovy index 37e8447e7bd..0eb0c91339f 100644 --- a/configurations/mongo-reactive/src/test/groovy/io/micronaut/configuration/mongo/reactive/MongoReactiveConfigurationSpec.groovy +++ b/configurations/mongo-reactive/src/test/groovy/io/micronaut/configuration/mongo/reactive/MongoReactiveConfigurationSpec.groovy @@ -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 diff --git a/configurations/netflix-archaius/src/main/java/io/micronaut/configurations/archaius1/EnvironmentConfiguration.java b/configurations/netflix-archaius/src/main/java/io/micronaut/configurations/archaius1/EnvironmentConfiguration.java index 36d80eb1ee2..27b43a741cc 100644 --- a/configurations/netflix-archaius/src/main/java/io/micronaut/configurations/archaius1/EnvironmentConfiguration.java +++ b/configurations/netflix-archaius/src/main/java/io/micronaut/configurations/archaius1/EnvironmentConfiguration.java @@ -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; @@ -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 diff --git a/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/AbstractRibbonClientConfig.java b/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/AbstractRibbonClientConfig.java index b57386a8589..ca32af71414 100644 --- a/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/AbstractRibbonClientConfig.java +++ b/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/AbstractRibbonClientConfig.java @@ -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; @@ -241,7 +242,8 @@ protected T get(IClientConfigKey key, Class 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() { diff --git a/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/discovery/RibbonDiscoveryClientLoadBalancerFactory.java b/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/discovery/RibbonDiscoveryClientLoadBalancerFactory.java index 7c76f404f01..56ccf5282b1 100644 --- a/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/discovery/RibbonDiscoveryClientLoadBalancerFactory.java +++ b/configurations/netflix-ribbon/src/main/java/io/micronaut/configurations/ribbon/discovery/RibbonDiscoveryClientLoadBalancerFactory.java @@ -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; @@ -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 serverList = beanContext.findBean(ServerList.class, Qualifiers.byName(serviceID)).orElseGet(() -> new DiscoveryClientServerList(getDiscoveryClient(), serviceID)); + String finalServiceID = serviceID; + ServerList 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); diff --git a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java index c8a16241969..b7ac8d8ce51 100644 --- a/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java +++ b/core/src/main/java/io/micronaut/core/convert/DefaultConversionService.java @@ -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); diff --git a/core/src/main/java/io/micronaut/core/convert/format/KeyFormat.java b/core/src/main/java/io/micronaut/core/convert/format/KeyFormat.java new file mode 100644 index 00000000000..63b6cefced6 --- /dev/null +++ b/core/src/main/java/io/micronaut/core/convert/format/KeyFormat.java @@ -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(); +} diff --git a/core/src/main/java/io/micronaut/core/naming/NameUtils.java b/core/src/main/java/io/micronaut/core/naming/NameUtils.java index 7957ad3fdf5..7fb64cff4cf 100644 --- a/core/src/main/java/io/micronaut/core/naming/NameUtils.java +++ b/core/src/main/java/io/micronaut/core/naming/NameUtils.java @@ -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); } /** @@ -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. * @@ -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; @@ -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) { @@ -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; + } } diff --git a/core/src/main/java/io/micronaut/core/naming/conventions/StringConvention.java b/core/src/main/java/io/micronaut/core/naming/conventions/StringConvention.java new file mode 100644 index 00000000000..a621ae2682f --- /dev/null +++ b/core/src/main/java/io/micronaut/core/naming/conventions/StringConvention.java @@ -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); + } + } +} diff --git a/core/src/main/java/io/micronaut/core/util/StringUtils.java b/core/src/main/java/io/micronaut/core/util/StringUtils.java index 5cfd51d5e7e..8a5c91b9777 100644 --- a/core/src/main/java/io/micronaut/core/util/StringUtils.java +++ b/core/src/main/java/io/micronaut/core/util/StringUtils.java @@ -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 internSetOf(Object... objects) { if (objects == null || objects.length == 0) { return Collections.emptySet(); @@ -104,6 +105,7 @@ public static Set internSetOf(Object... objects) { * @return An unmodifiable set of strings * @see CollectionUtils#mapOf(Object...) */ + @SuppressWarnings("unused") public static Map internMapOf(Object... values) { if (values == null) { return Collections.emptyMap(); diff --git a/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy b/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy index 6ed37c7ba8f..7061177a7f1 100644 --- a/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy +++ b/core/src/test/groovy/io/micronaut/core/naming/NameUtilsSpec.groovy @@ -17,6 +17,7 @@ package io.micronaut.core.naming import spock.lang.Specification +import spock.lang.Unroll /** * @author Graeme Rocher @@ -31,24 +32,58 @@ class NameUtilsSpec extends Specification { value | result "com.fooBar.FooBar" | "FooBar" "FooBar" | "FooBar" - "com.bar.\$FooBar" | "\$FooBar" + "com.bar.\$FooBar" | "\$FooBar" } - void "test hyphenate"() { + @Unroll + void "test camel case value #value"() { + expect: + NameUtils.camelCase(value) == result + + where: + value | result + 'micronaut.config-client.enabled' | 'micronaut.configClient.enabled' + 'foo-bar' | 'fooBar' + } + + + @Unroll + void "test hyphenate #value"() { expect: NameUtils.hyphenate(value) == result + where: + value | result + 'micronaut.config-client.enabled' | 'micronaut.config-client.enabled' + "com.fooBar.FooBar" | "com.foo-bar.foo-bar" + "FooBar" | "foo-bar" + "com.bar.FooBar" | "com.bar.foo-bar" + "Foo" | 'foo' + "FooBBar" | 'foo-bbar' + "FOO_BAR" | 'foo-bar' + "fooBBar" | 'foo-bbar' + } + + @Unroll + void "test environment name separate #value"() { + expect: + NameUtils.environmentName(value) == result + where: value | result - "com.fooBar.FooBar" | "com.foo-bar.foo-bar" - "FooBar" | "foo-bar" - "com.bar.FooBar" | "com.bar.foo-bar" - "Foo" | 'foo' - "FooBBar" | 'foo-bbar' - "fooBBar" | 'foo-bbar' + "com.fooBar.FooBar" | "COM_FOO_BAR_FOO_BAR" + "FooBar" | "FOO_BAR" + "com.bar.FooBar" | "COM_BAR_FOO_BAR" + "Foo" | 'FOO' + "FooBBar" | 'FOO_BBAR' + "FOO_BAR" | 'FOO_BAR' + "FOO-BAR" | 'FOO_BAR' + "foo-bar-baz" | 'FOO_BAR_BAZ' + "fooBBar" | 'FOO_BBAR' } - void "test hyphenate no lower case"() { + @Unroll + void "test hyphenate #value - no lower case"() { expect: NameUtils.hyphenate(value, false) == result @@ -58,6 +93,7 @@ class NameUtilsSpec extends Specification { "FooBar" | "Foo-Bar" "com.bar.FooBar" | "com.bar.Foo-Bar" "Foo" | 'Foo' + "FOO_BAR" | 'FOO-BAR' "FooBBar" | 'Foo-BBar' } diff --git a/discovery-client/src/main/java/io/micronaut/discovery/aws/route53/Route53ClientDiscoveryConfiguration.java b/discovery-client/src/main/java/io/micronaut/discovery/aws/route53/Route53ClientDiscoveryConfiguration.java index 1c5ce591c67..3eac61d228c 100644 --- a/discovery-client/src/main/java/io/micronaut/discovery/aws/route53/Route53ClientDiscoveryConfiguration.java +++ b/discovery-client/src/main/java/io/micronaut/discovery/aws/route53/Route53ClientDiscoveryConfiguration.java @@ -36,7 +36,7 @@ public class Route53ClientDiscoveryConfiguration extends DiscoveryClientConfiguration { public static final String SERVICE_ID = "route53"; - @Value("${aws.route53.discovery.client.awsServiceId}") + @Value("${aws.route53.discovery.client.aws-service-id}") String awsServiceId; //ID of the service - required to find it String namespaceId; // used to filter a list of available services attached to a namespace diff --git a/discovery-client/src/main/java/io/micronaut/discovery/client/DiscoveryClientCacheConfiguration.java b/discovery-client/src/main/java/io/micronaut/discovery/client/DiscoveryClientCacheConfiguration.java index 4c36e5f1059..d3013bb8e91 100644 --- a/discovery-client/src/main/java/io/micronaut/discovery/client/DiscoveryClientCacheConfiguration.java +++ b/discovery-client/src/main/java/io/micronaut/discovery/client/DiscoveryClientCacheConfiguration.java @@ -40,12 +40,12 @@ public class DiscoveryClientCacheConfiguration extends CacheConfiguration implem /** * The prefix to use for all discovery client settings */ - public static final String CACHE_NAME = "discoveryClient"; + public static final String CACHE_NAME = "discovery-client"; /** * Configuration property name for enabled discovery cache client */ - public static final String SETTING_ENABLED = CacheConfiguration.PREFIX + ".discoveryClient.enabled"; + public static final String SETTING_ENABLED = CacheConfiguration.PREFIX + ".discovery-client.enabled"; private boolean enabled = true; diff --git a/discovery-client/src/main/java/io/micronaut/discovery/consul/client/v1/AbstractConsulClient.java b/discovery-client/src/main/java/io/micronaut/discovery/consul/client/v1/AbstractConsulClient.java index 389dc551d65..98fe7db91fa 100644 --- a/discovery-client/src/main/java/io/micronaut/discovery/consul/client/v1/AbstractConsulClient.java +++ b/discovery-client/src/main/java/io/micronaut/discovery/consul/client/v1/AbstractConsulClient.java @@ -17,6 +17,7 @@ import io.micronaut.context.annotation.Requires; import io.micronaut.core.async.publisher.Publishers; +import io.micronaut.core.naming.NameUtils; import io.micronaut.discovery.DiscoveryClient; import io.micronaut.discovery.ServiceInstance; import io.micronaut.discovery.consul.ConsulConfiguration; @@ -59,6 +60,7 @@ public String getDescription() { @Override public Publisher> getInstances(String serviceId) { + serviceId = NameUtils.hyphenate(serviceId); if (SERVICE_ID.equals(serviceId)) { return Publishers.just( Collections.singletonList(ServiceInstance.of(SERVICE_ID, consulConfiguration.getHost(), consulConfiguration.getPort())) diff --git a/discovery-client/src/main/java/io/micronaut/discovery/eureka/EurekaConfiguration.java b/discovery-client/src/main/java/io/micronaut/discovery/eureka/EurekaConfiguration.java index bfb1e090e47..0fbd9e86ab8 100644 --- a/discovery-client/src/main/java/io/micronaut/discovery/eureka/EurekaConfiguration.java +++ b/discovery-client/src/main/java/io/micronaut/discovery/eureka/EurekaConfiguration.java @@ -19,6 +19,7 @@ import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.context.annotation.Requires; import io.micronaut.context.annotation.Value; +import io.micronaut.context.env.Environment; import io.micronaut.discovery.DiscoveryConfiguration; import io.micronaut.discovery.client.DiscoveryClientConfiguration; import io.micronaut.discovery.eureka.client.v2.DataCenterInfo; @@ -137,40 +138,45 @@ public static class EurekaRegistrationConfiguration extends RegistrationConfigur public static final String IP_ADDRESS = EurekaConfiguration.PREFIX + '.' + RegistrationConfiguration.PREFIX + '.' + - "ipAddr"; + "ip-addr"; @ConfigurationBuilder InstanceInfo instanceInfo; - @ConfigurationBuilder(configurationPrefix = "leaseInfo") + @ConfigurationBuilder(configurationPrefix = "lease-info") LeaseInfo.Builder leaseInfo = LeaseInfo.Builder.newBuilder(); private final boolean explicitInstanceId; public EurekaRegistrationConfiguration( EmbeddedServer embeddedServer, - @Value("${" + ApplicationConfiguration.APPLICATION_NAME + "}") String applicationName, - @Value("${" + EurekaRegistrationConfiguration.IP_ADDRESS + "}") Optional ipAddress, - @Value("${" + ApplicationConfiguration.InstanceConfiguration.INSTANCE_ID + "}") Optional instanceId, - Optional dataCenterInfo) { - this.explicitInstanceId = instanceId.isPresent(); - if (ipAddress.isPresent()) { + ApplicationConfiguration applicationConfiguration, + @Value("${" + EurekaRegistrationConfiguration.IP_ADDRESS + "}") @Nullable String ipAddress, + @Nullable DataCenterInfo dataCenterInfo) { + String instanceId = applicationConfiguration.getInstance().getId().orElse(null); + String applicationName = applicationConfiguration.getName().orElse(Environment.DEFAULT_NAME); + this.explicitInstanceId = instanceId != null; + if (ipAddress != null) { this.instanceInfo = new InstanceInfo( embeddedServer.getHost(), embeddedServer.getPort(), - ipAddress.get(), + ipAddress, applicationName, - instanceId.orElse(applicationName)); + explicitInstanceId ? instanceId : applicationName + ); } else { this.instanceInfo = new InstanceInfo( embeddedServer.getHost(), embeddedServer.getPort(), applicationName, - instanceId.orElse(applicationName)); + explicitInstanceId ? instanceId : applicationName + ); } - dataCenterInfo.ifPresent(dci -> this.instanceInfo.setDataCenterInfo(dci)); + if(dataCenterInfo != null) { + this.instanceInfo.setDataCenterInfo(dataCenterInfo); + } } /** diff --git a/discovery-client/src/main/java/io/micronaut/discovery/eureka/client/v2/AbstractEurekaClient.java b/discovery-client/src/main/java/io/micronaut/discovery/eureka/client/v2/AbstractEurekaClient.java index 7b8e8d742c9..5ab5e06c842 100644 --- a/discovery-client/src/main/java/io/micronaut/discovery/eureka/client/v2/AbstractEurekaClient.java +++ b/discovery-client/src/main/java/io/micronaut/discovery/eureka/client/v2/AbstractEurekaClient.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; import io.micronaut.core.async.publisher.Publishers; +import io.micronaut.core.naming.NameUtils; import io.micronaut.discovery.ServiceInstance; import io.micronaut.discovery.eureka.EurekaConfiguration; import io.micronaut.discovery.eureka.EurekaServiceInstance; @@ -65,6 +66,7 @@ public String getDescription() { @Override public Publisher> getInstances(String serviceId) { + serviceId = NameUtils.hyphenate(serviceId); Flowable> flowable = Flowable.fromPublisher(getApplicationInfo(serviceId)).map(applicationInfo -> { List instances = applicationInfo.getInstances(); return instances.stream() diff --git a/discovery-client/src/main/java/io/micronaut/discovery/kubernetes/KubernetesDiscoveryClient.java b/discovery-client/src/main/java/io/micronaut/discovery/kubernetes/KubernetesDiscoveryClient.java index 4da5363c6f0..3d4f0fbcd37 100644 --- a/discovery-client/src/main/java/io/micronaut/discovery/kubernetes/KubernetesDiscoveryClient.java +++ b/discovery-client/src/main/java/io/micronaut/discovery/kubernetes/KubernetesDiscoveryClient.java @@ -16,6 +16,7 @@ package io.micronaut.discovery.kubernetes; import io.micronaut.context.annotation.Requires; +import io.micronaut.core.naming.NameUtils; import io.micronaut.core.util.StringUtils; import io.micronaut.discovery.DiscoveryClient; import io.micronaut.discovery.ServiceInstance; @@ -42,7 +43,7 @@ public class KubernetesDiscoveryClient implements DiscoveryClient { @Override public Flowable> getInstances(String serviceId) { - + serviceId = NameUtils.hyphenate(serviceId); Map environment = resolveEnvironment(); String envName = serviceId.toUpperCase(Locale.ENGLISH).replace('-', '_'); diff --git a/discovery-client/src/test/groovy/io/micronaut/discovery/consul/ConsulMockHealthStatusSpec.groovy b/discovery-client/src/test/groovy/io/micronaut/discovery/consul/ConsulMockHealthStatusSpec.groovy index 9745d947448..3fc7f97dba3 100644 --- a/discovery-client/src/test/groovy/io/micronaut/discovery/consul/ConsulMockHealthStatusSpec.groovy +++ b/discovery-client/src/test/groovy/io/micronaut/discovery/consul/ConsulMockHealthStatusSpec.groovy @@ -57,7 +57,7 @@ class ConsulMockHealthStatusSpec extends Specification { when:"An application is set to fail" - HttpStatus status = Flowable.fromPublisher(consulClient.fail("service:myService:${application.port}")).blockingFirst() + HttpStatus status = Flowable.fromPublisher(consulClient.fail("service:my-service:${application.port}")).blockingFirst() then:"The status is ok" status == HttpStatus.OK diff --git a/discovery-client/src/test/groovy/io/micronaut/discovery/consul/MockConsulAuth.groovy b/discovery-client/src/test/groovy/io/micronaut/discovery/consul/MockConsulAuth.groovy index f3845c165a1..cfdba355f02 100644 --- a/discovery-client/src/test/groovy/io/micronaut/discovery/consul/MockConsulAuth.groovy +++ b/discovery-client/src/test/groovy/io/micronaut/discovery/consul/MockConsulAuth.groovy @@ -15,17 +15,6 @@ */ package io.micronaut.discovery.consul -import io.micronaut.context.annotation.Requires -import io.micronaut.context.annotation.Value -import io.micronaut.core.async.publisher.Publishers -import io.micronaut.core.util.Toggleable -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.HttpStatus -import io.micronaut.http.MutableHttpResponse -import io.micronaut.http.annotation.Filter -import io.micronaut.http.filter.HttpServerFilter -import io.micronaut.http.filter.ServerFilterChain import io.micronaut.context.annotation.Requires import io.micronaut.context.annotation.Value import io.micronaut.core.async.publisher.Publishers @@ -44,12 +33,12 @@ import org.reactivestreams.Publisher * @since 1.0 */ @Filter('/v1/**') -@Requires('consul.client.aslToken') +@Requires('consul.client.asl-token') class MockConsulAuth implements HttpServerFilter, Toggleable{ final Optional token - MockConsulAuth(@Value('${consul.client.aslToken}') Optional token) { + MockConsulAuth(@Value('${consul.client.asl-token}') Optional token) { this.token = token } diff --git a/discovery-client/src/test/groovy/io/micronaut/discovery/consul/TtlHeartbeatSpec.groovy b/discovery-client/src/test/groovy/io/micronaut/discovery/consul/TtlHeartbeatSpec.groovy index 991770bbe4d..22ad28da45c 100644 --- a/discovery-client/src/test/groovy/io/micronaut/discovery/consul/TtlHeartbeatSpec.groovy +++ b/discovery-client/src/test/groovy/io/micronaut/discovery/consul/TtlHeartbeatSpec.groovy @@ -16,6 +16,7 @@ package io.micronaut.discovery.consul import io.micronaut.context.ApplicationContext +import io.micronaut.core.naming.NameUtils import io.reactivex.Flowable import io.micronaut.context.ApplicationContext import io.micronaut.discovery.DiscoveryClient @@ -56,7 +57,7 @@ class TtlHeartbeatSpec extends Specification implements MockConsulSpec { conditions.eventually { Flowable.fromPublisher(discoveryClient.getInstances(serviceId)).blockingFirst().size() == 1 Flowable.fromPublisher(discoveryClient.getInstances(serviceId)).blockingFirst().size() == 1 - MockConsulServer.passingReports.find { it.contains(serviceId)} != null + MockConsulServer.passingReports.find { it.contains(NameUtils.hyphenate(serviceId))} != null } cleanup: diff --git a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockAutoRegistrationSpec.groovy b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockAutoRegistrationSpec.groovy index 27fb2df9e58..35efe46ba9e 100644 --- a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockAutoRegistrationSpec.groovy +++ b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockAutoRegistrationSpec.groovy @@ -16,6 +16,7 @@ package io.micronaut.discovery.eureka import io.micronaut.context.ApplicationContext +import io.micronaut.core.naming.NameUtils import io.micronaut.discovery.DiscoveryClient import io.micronaut.discovery.eureka.client.v2.EurekaClient import io.micronaut.discovery.eureka.client.v2.InstanceInfo @@ -62,12 +63,12 @@ class EurekaMockAutoRegistrationSpec extends Specification { then: "The application is registered" conditions.eventually { Flowable.fromPublisher(eurekaClient.applicationInfos).blockingFirst().size() == 1 - Flowable.fromPublisher(eurekaClient.getApplicationVips(serviceId)).blockingFirst().size() == 1 - Flowable.fromPublisher(eurekaClient.getInstances(serviceId)).blockingFirst().size() == 1 - Flowable.fromPublisher(eurekaClient.getServiceIds()).blockingFirst().contains(serviceId) - MockEurekaServer.instances[serviceId].size() == 1 + Flowable.fromPublisher(eurekaClient.getApplicationVips(NameUtils.hyphenate(serviceId))).blockingFirst().size() == 1 + Flowable.fromPublisher(eurekaClient.getInstances(NameUtils.hyphenate(serviceId))).blockingFirst().size() == 1 + Flowable.fromPublisher(eurekaClient.getServiceIds()).blockingFirst().contains(NameUtils.hyphenate(serviceId)) + MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].size() == 1 - InstanceInfo instanceInfo = MockEurekaServer.instances[serviceId].values().first() + InstanceInfo instanceInfo = MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].values().first() instanceInfo.status == InstanceInfo.Status.UP } @@ -78,7 +79,7 @@ class EurekaMockAutoRegistrationSpec extends Specification { then: "The application is de-registered" conditions.eventually { - MockEurekaServer.instances[serviceId].size() == 0 + MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].size() == 0 } when:"test validation" @@ -122,9 +123,9 @@ class EurekaMockAutoRegistrationSpec extends Specification { expect: "The metadata is correct" conditions.eventually { Flowable.fromPublisher(discoveryClient.getInstances(serviceId)).blockingFirst().size() == 1 - MockEurekaServer.instances[serviceId].size() == 1 + MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].size() == 1 - InstanceInfo instanceInfo = MockEurekaServer.instances[serviceId].values().first() + InstanceInfo instanceInfo = MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].values().first() configuration.every { instanceInfo."$it.key" == it.value } diff --git a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockHeartbeatSpec.groovy b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockHeartbeatSpec.groovy index d7933b6242c..a35c0ffad8d 100644 --- a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockHeartbeatSpec.groovy +++ b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/EurekaMockHeartbeatSpec.groovy @@ -16,14 +16,12 @@ package io.micronaut.discovery.eureka import io.micronaut.context.ApplicationContext -import io.micronaut.discovery.eureka.client.v2.EurekaClient -import io.micronaut.discovery.eureka.client.v2.InstanceInfo -import io.reactivex.Flowable -import io.micronaut.context.ApplicationContext +import io.micronaut.core.naming.NameUtils import io.micronaut.discovery.DiscoveryClient import io.micronaut.discovery.eureka.client.v2.EurekaClient import io.micronaut.discovery.eureka.client.v2.InstanceInfo import io.micronaut.runtime.server.EmbeddedServer +import io.reactivex.Flowable import spock.lang.Specification import spock.util.concurrent.PollingConditions @@ -60,12 +58,12 @@ class EurekaMockHeartbeatSpec extends Specification { then: "The application is registered" conditions.eventually { Flowable.fromPublisher(discoveryClient.getInstances(serviceId)).blockingFirst().size() == 1 - MockEurekaServer.instances[serviceId].size() == 1 + MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].size() == 1 - InstanceInfo instanceInfo = MockEurekaServer.instances[serviceId].values().first() + InstanceInfo instanceInfo = MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].values().first() instanceInfo.status == InstanceInfo.Status.UP // heart beat received - MockEurekaServer.heartbeats[serviceId].values().first() + MockEurekaServer.heartbeats[NameUtils.hyphenate(serviceId)].values().first() } when: "The application is stopped" @@ -73,7 +71,7 @@ class EurekaMockHeartbeatSpec extends Specification { then: "The application is de-registered" conditions.eventually { - MockEurekaServer.instances[serviceId].size() == 0 + MockEurekaServer.instances[NameUtils.hyphenate(serviceId)].size() == 0 } cleanup: diff --git a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaAuth.groovy b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaAuth.groovy index beef4aafc7a..b47fce4b99e 100644 --- a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaAuth.groovy +++ b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaAuth.groovy @@ -18,22 +18,7 @@ package io.micronaut.discovery.eureka import io.micronaut.context.annotation.Requires import io.micronaut.context.annotation.Value import io.micronaut.core.async.publisher.Publishers -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.HttpStatus -import io.micronaut.http.MutableHttpResponse -import io.micronaut.http.annotation.Filter -import io.micronaut.http.filter.HttpServerFilter -import io.micronaut.http.filter.ServerFilterChain -import io.micronaut.context.annotation.Requires -import io.micronaut.context.annotation.Value -import io.micronaut.core.async.publisher.Publishers -import io.micronaut.http.HttpHeaders -import io.micronaut.http.HttpRequest -import io.micronaut.http.HttpResponse -import io.micronaut.http.HttpStatus -import io.micronaut.http.MutableHttpResponse +import io.micronaut.http.* import io.micronaut.http.annotation.Filter import io.micronaut.http.filter.HttpServerFilter import io.micronaut.http.filter.ServerFilterChain diff --git a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaServer.groovy b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaServer.groovy index 5107ba7971f..1b9049a7f34 100644 --- a/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaServer.groovy +++ b/discovery-client/src/test/groovy/io/micronaut/discovery/eureka/MockEurekaServer.groovy @@ -17,22 +17,7 @@ package io.micronaut.discovery.eureka import io.micronaut.context.annotation.Requires import io.micronaut.core.async.publisher.Publishers -import io.micronaut.discovery.eureka.client.v2.ApplicationInfo -import io.micronaut.discovery.eureka.client.v2.EurekaOperations -import io.micronaut.discovery.eureka.client.v2.InstanceInfo -import io.micronaut.discovery.eureka.client.v2.MockApplicationInfo -import io.micronaut.discovery.eureka.client.v2.MockApplicationInfos -import io.micronaut.http.HttpStatus -import io.micronaut.http.annotation.Body -import io.micronaut.http.annotation.Controller -import io.micronaut.http.annotation.Get -import io.micronaut.context.annotation.Requires -import io.micronaut.core.async.publisher.Publishers -import io.micronaut.discovery.eureka.client.v2.ApplicationInfo -import io.micronaut.discovery.eureka.client.v2.EurekaOperations -import io.micronaut.discovery.eureka.client.v2.InstanceInfo -import io.micronaut.discovery.eureka.client.v2.MockApplicationInfo -import io.micronaut.discovery.eureka.client.v2.MockApplicationInfos +import io.micronaut.discovery.eureka.client.v2.* import io.micronaut.http.HttpStatus import io.micronaut.http.annotation.Body import io.micronaut.http.annotation.Controller @@ -41,7 +26,8 @@ import org.reactivestreams.Publisher import javax.inject.Singleton import javax.validation.Valid -import javax.validation.constraints.* +import javax.validation.constraints.NotBlank +import javax.validation.constraints.NotNull import java.util.concurrent.ConcurrentHashMap /** diff --git a/function-web/src/main/java/io/micronaut/function/web/AnnotatedFunctionRouteBuilder.java b/function-web/src/main/java/io/micronaut/function/web/AnnotatedFunctionRouteBuilder.java index 3a02bbeb534..f726bc62f96 100644 --- a/function-web/src/main/java/io/micronaut/function/web/AnnotatedFunctionRouteBuilder.java +++ b/function-web/src/main/java/io/micronaut/function/web/AnnotatedFunctionRouteBuilder.java @@ -79,7 +79,7 @@ public AnnotatedFunctionRouteBuilder( UriNamingStrategy uriNamingStrategy, ConversionService conversionService, MediaTypeCodecRegistry codecRegistry, - @Value("${function.contextPath:/}") String contextPath) { + @Value("${function.context-path:/}") String contextPath) { super(executionHandleLocator, uriNamingStrategy, conversionService); this.localFunctionRegistry = new DefaultLocalFunctionRegistry(codecRegistry); this.contextPath = contextPath.endsWith("/") ? contextPath : contextPath + '/'; diff --git a/http-client/src/main/java/io/micronaut/http/client/DefaultLoadBalancerResolver.java b/http-client/src/main/java/io/micronaut/http/client/DefaultLoadBalancerResolver.java index 42e98c810e0..89320e4e594 100644 --- a/http-client/src/main/java/io/micronaut/http/client/DefaultLoadBalancerResolver.java +++ b/http-client/src/main/java/io/micronaut/http/client/DefaultLoadBalancerResolver.java @@ -16,6 +16,7 @@ package io.micronaut.http.client; import io.micronaut.context.BeanContext; +import io.micronaut.core.naming.NameUtils; import io.micronaut.core.util.ArrayUtils; import io.micronaut.core.util.StringUtils; import io.micronaut.discovery.DiscoveryClient; @@ -94,6 +95,7 @@ public Optional resolve(String... serviceReferences) { return Optional.empty(); } } else { + reference = NameUtils.hyphenate(reference); return resolveLoadBalancerForServiceID(reference); } } diff --git a/inject-groovy/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.groovy b/inject-groovy/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.groovy index 5aa51e57856..cfe32ca462f 100644 --- a/inject-groovy/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.groovy +++ b/inject-groovy/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.groovy @@ -14,7 +14,7 @@ * limitations under the License. */ @Configuration -@Requires(property = "dataSource.url") +@Requires(property = "data-source.url") package io.micronaut.inject.configurations.requiresproperty import io.micronaut.context.annotation.Configuration diff --git a/inject-java/src/main/java/io/micronaut/annotation/processing/BeanDefinitionInjectProcessor.java b/inject-java/src/main/java/io/micronaut/annotation/processing/BeanDefinitionInjectProcessor.java index 294e470fea4..61eb61313fe 100644 --- a/inject-java/src/main/java/io/micronaut/annotation/processing/BeanDefinitionInjectProcessor.java +++ b/inject-java/src/main/java/io/micronaut/annotation/processing/BeanDefinitionInjectProcessor.java @@ -101,10 +101,10 @@ public boolean process(Set annotations, RoundEnvironment JavaVisitorContext visitorContext = new JavaVisitorContext(processingEnv.getMessager()); SoftServiceLoader serviceLoader = SoftServiceLoader.load(TypeElementVisitor.class, getClass().getClassLoader()); - List loadedVisitors = new ArrayList<>(); + Map loadedVisitors = new HashMap<>(); for (ServiceDefinition definition: serviceLoader) { if (definition.isPresent()) { - loadedVisitors.add(new LoadedVisitor(definition.load(), visitorContext, genericUtils, processingEnv, annotationUtils)); + loadedVisitors.put(definition.getName(), new LoadedVisitor(definition.load(), visitorContext, genericUtils, processingEnv, annotationUtils)); } } @@ -125,7 +125,7 @@ public boolean process(Set annotations, RoundEnvironment String name = typeElement.getQualifiedName().toString(); if (!beanDefinitionWriters.containsKey(name)) { if (!processed.contains(name) && !name.endsWith(BeanDefinitionVisitor.PROXY_SUFFIX)) { - Stream matchedVisitors = loadedVisitors.stream().filter((v) -> v.matches(typeElement)); + Stream matchedVisitors = loadedVisitors.values().stream().filter((v) -> v.matches(typeElement)); boolean isInterface = typeElement.getKind() == ElementKind.INTERFACE; if (!isInterface) { if (!processed.contains(name) && !name.endsWith(BeanDefinitionVisitor.PROXY_SUFFIX)) { diff --git a/inject-java/src/test/groovy/io/micronaut/inject/configproperties/ConfigPropertiesParseSpec.groovy b/inject-java/src/test/groovy/io/micronaut/inject/configproperties/ConfigPropertiesParseSpec.groovy index d7737ab3a77..4f48b1917e0 100644 --- a/inject-java/src/test/groovy/io/micronaut/inject/configproperties/ConfigPropertiesParseSpec.groovy +++ b/inject-java/src/test/groovy/io/micronaut/inject/configproperties/ConfigPropertiesParseSpec.groovy @@ -535,9 +535,9 @@ class Parent { beanDefinition.injectedMethods.size() == 2 beanDefinition.injectedMethods[0].name == 'setParentTest' beanDefinition.injectedMethods[0].getAnnotationMetadata().hasAnnotation(Property) - beanDefinition.injectedMethods[0].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.parentTest' + beanDefinition.injectedMethods[0].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.parent-test' beanDefinition.injectedMethods[1].getAnnotationMetadata().hasAnnotation(Property) - beanDefinition.injectedMethods[1].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.setterTest' + beanDefinition.injectedMethods[1].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.setter-test' beanDefinition.injectedMethods[1].name == 'setSetterTest' diff --git a/inject-java/src/test/groovy/io/micronaut/inject/configuration/JavaConfigurationMetadataBuilderSpec.groovy b/inject-java/src/test/groovy/io/micronaut/inject/configuration/JavaConfigurationMetadataBuilderSpec.groovy index 230f741ac4c..f652e710d72 100644 --- a/inject-java/src/test/groovy/io/micronaut/inject/configuration/JavaConfigurationMetadataBuilderSpec.groovy +++ b/inject-java/src/test/groovy/io/micronaut/inject/configuration/JavaConfigurationMetadataBuilderSpec.groovy @@ -68,7 +68,7 @@ class MyProperties { builder.properties.size() == 1 propertyMetadata.name == 'setterTest' - propertyMetadata.path == 'foo.setterTest' + propertyMetadata.path == 'foo.setter-test' propertyMetadata.type == 'java.lang.String' propertyMetadata.declaringType == 'test.MyProperties' propertyMetadata.description == 'some description' @@ -237,7 +237,7 @@ class ParentProperties { builder.properties.size() == 1 builder.properties[0].name == 'setterTest' - builder.properties[0].path == 'parent.child.setterTest' + builder.properties[0].path == 'parent.child.setter-test' builder.properties[0].type == 'java.lang.String' builder.properties[0].declaringType == 'test.ChildProperties' builder.properties[0].description == 'some description' @@ -279,7 +279,7 @@ class GrandParentProperties { builder.properties.size() == 1 builder.properties[0].name == 'setterTest' - builder.properties[0].path == 'grand.parent.child.setterTest' + builder.properties[0].path == 'grand.parent.child.setter-test' builder.properties[0].type == 'java.lang.String' builder.properties[0].declaringType == 'test.ChildProperties' builder.properties[0].description == 'some description' @@ -382,13 +382,13 @@ class GrandParentProperties { then: builder.configurations.size() == 1 - builder.configurations[0].name == 'grand.parent.child.innerParent.inner' + builder.configurations[0].name == 'grand.parent.child.inner-parent.inner' builder.configurations[0].description == 'some description' builder.configurations[0].type == 'test.ChildProperties$InnerProperties' builder.properties.size() == 1 builder.properties[0].name == 'foo' - builder.properties[0].path == 'grand.parent.child.innerParent.inner.foo' + builder.properties[0].path == 'grand.parent.child.inner-parent.inner.foo' builder.properties[0].type == 'java.lang.String' builder.properties[0].declaringType == 'test.ChildProperties$InnerProperties' builder.properties[0].description == 'some description' diff --git a/inject-java/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.java b/inject-java/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.java index 4acde94f5fa..0b3724a1868 100644 --- a/inject-java/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.java +++ b/inject-java/src/test/groovy/io/micronaut/inject/configurations/requiresproperty/package-info.java @@ -14,7 +14,7 @@ * limitations under the License. */ @Configuration -@Requires(property = "dataSource.url") +@Requires(property = "data-source.url") package io.micronaut.inject.configurations.requiresproperty; import io.micronaut.context.annotation.Configuration; diff --git a/inject-java/src/test/groovy/io/micronaut/inject/foreach/EachPropertyParseSpec.groovy b/inject-java/src/test/groovy/io/micronaut/inject/foreach/EachPropertyParseSpec.groovy index aaa8a86397c..1304a4a544b 100644 --- a/inject-java/src/test/groovy/io/micronaut/inject/foreach/EachPropertyParseSpec.groovy +++ b/inject-java/src/test/groovy/io/micronaut/inject/foreach/EachPropertyParseSpec.groovy @@ -62,9 +62,9 @@ class Parent { beanDefinition.injectedMethods.size() == 2 beanDefinition.injectedMethods[0].name == 'setParentTest' beanDefinition.injectedMethods[0].getAnnotationMetadata().hasAnnotation(Property) - beanDefinition.injectedMethods[0].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.*.parentTest' + beanDefinition.injectedMethods[0].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.*.parent-test' beanDefinition.injectedMethods[1].getAnnotationMetadata().hasAnnotation(Property) - beanDefinition.injectedMethods[1].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.*.setterTest' + beanDefinition.injectedMethods[1].getAnnotationMetadata().getAnnotation(Property).name() == 'foo.*.setter-test' beanDefinition.injectedMethods[1].name == 'setSetterTest' } diff --git a/inject/src/main/java/io/micronaut/context/AbstractBeanDefinition.java b/inject/src/main/java/io/micronaut/context/AbstractBeanDefinition.java index 17f0209cbf7..927d946c969 100644 --- a/inject/src/main/java/io/micronaut/context/AbstractBeanDefinition.java +++ b/inject/src/main/java/io/micronaut/context/AbstractBeanDefinition.java @@ -43,6 +43,7 @@ import io.micronaut.core.annotation.Internal; import io.micronaut.core.convert.ArgumentConversionContext; import io.micronaut.core.convert.ConversionContext; +import io.micronaut.core.naming.NameUtils; import io.micronaut.core.naming.Named; import io.micronaut.core.reflect.GenericTypeUtils; import io.micronaut.core.reflect.ReflectionUtils; @@ -961,7 +962,17 @@ protected final Object getValueForConstructorArgument(BeanResolutionContext reso return resolveOptionalObject(value); } else { // can't use orElseThrow here due to compiler bug - result = value.orElseThrow(() -> new DependencyInjectionException(resolutionContext, conversionContext, prop)); + if(value.isPresent()) { + result = value.get(); + } + else { + if(argument.getAnnotation(Nullable.class) != null) { + result = null; + } + else { + throw new DependencyInjectionException(resolutionContext, conversionContext, prop); + } + } } } else { throw new DependencyInjectionException(resolutionContext, argument, "BeanContext must support property resolution"); @@ -1453,7 +1464,7 @@ private String resolvePropertyPath( String path) { String valString = getConfigurationPropertiesPath(resolutionContext); - return valString + "." + path; + return NameUtils.hyphenate(valString + "." + path, true); } private String getConfigurationPropertiesPath(BeanResolutionContext resolutionContext) { diff --git a/inject/src/main/java/io/micronaut/context/env/DefaultPropertyPlaceholderResolver.java b/inject/src/main/java/io/micronaut/context/env/DefaultPropertyPlaceholderResolver.java index 9f93f73b528..f5fcf6e29de 100644 --- a/inject/src/main/java/io/micronaut/context/env/DefaultPropertyPlaceholderResolver.java +++ b/inject/src/main/java/io/micronaut/context/env/DefaultPropertyPlaceholderResolver.java @@ -33,16 +33,19 @@ public class DefaultPropertyPlaceholderResolver implements PropertyPlaceholderRe * Prefix for placeholder in properties */ public static final String PREFIX = "${"; + private final PropertyResolver environment; + private final String prefix; public DefaultPropertyPlaceholderResolver(PropertyResolver environment) { this.environment = environment; + this.prefix = PREFIX; } @Override public Optional resolvePlaceholders(String str) { try { - int i = str.indexOf(PREFIX); + int i = str.indexOf(prefix); if (i > -1) { return Optional.of(resolvePlaceholders(str, i)); } @@ -54,7 +57,7 @@ public Optional resolvePlaceholders(String str) { @Override public String resolveRequiredPlaceholders(String str) throws ConfigurationException { - int i = str.indexOf(PREFIX); + int i = str.indexOf(prefix); if (i > -1) { return resolvePlaceholders(str, i); } @@ -72,7 +75,7 @@ private String resolvePlaceholders(String str, int startIndex) { } resolveExpression(builder, str, expr); - i = restOfString.indexOf(PREFIX); + i = restOfString.indexOf(prefix); if (i > -1) { builder.append(resolvePlaceholders(restOfString, i)); } else { diff --git a/inject/src/main/java/io/micronaut/context/env/PropertySourcePropertyResolver.java b/inject/src/main/java/io/micronaut/context/env/PropertySourcePropertyResolver.java index 3837a025b41..44a00b44f70 100644 --- a/inject/src/main/java/io/micronaut/context/env/PropertySourcePropertyResolver.java +++ b/inject/src/main/java/io/micronaut/context/env/PropertySourcePropertyResolver.java @@ -17,6 +17,8 @@ import io.micronaut.core.convert.ArgumentConversionContext; import io.micronaut.core.convert.ConversionService; +import io.micronaut.core.convert.format.KeyFormat; +import io.micronaut.core.naming.NameUtils; import io.micronaut.core.util.CollectionUtils; import io.micronaut.core.util.StringUtils; import io.micronaut.core.value.MapPropertyResolver; @@ -184,7 +186,7 @@ public Optional getProperty(@Nullable String name, ArgumentConversionCont value = resolvePlaceHoldersIfNecessary(value); return conversionService.convert(value, conversionContext); } else if (Properties.class.isAssignableFrom(requiredType)) { - Properties properties = resolveSubProperties(name, entries); + Properties properties = resolveSubProperties(name, entries, conversionContext); return Optional.of((T) properties); } else if (Map.class.isAssignableFrom(requiredType)) { Map subMap = resolveSubMap(name, entries); @@ -247,9 +249,10 @@ private Object resolvePlaceHoldersIfNecessary(Object value) { } - protected Properties resolveSubProperties(String name, Map entries) { + protected Properties resolveSubProperties(String name, Map entries, ArgumentConversionContext conversionContext) { // special handling for maps for resolving sub keys Properties properties = new Properties(); + KeyFormat keyFormat = conversionContext.getAnnotation(KeyFormat.class); String prefix = name + '.'; entries.entrySet().stream() .filter(map -> map.getKey().startsWith(prefix)) @@ -257,6 +260,9 @@ protected Properties resolveSubProperties(String name, Map entri Object value = entry.getValue(); if (value != null) { String key = entry.getKey().substring(prefix.length()); + if(keyFormat != null) { + key = keyFormat.value().format(key); + } properties.put(key, resolvePlaceHoldersIfNecessary(value.toString())); } }); @@ -339,26 +345,12 @@ protected void processPropertySource(PropertySource properties, PropertySource.P private List resolvePropertiesForConvention(String property, PropertySource.PropertyConvention convention) { switch (convention) { case ENVIRONMENT_VARIABLE: - List properties = new ArrayList<>(); - String[] tokens = property.split("_"); - - StringBuilder path = new StringBuilder(); - int len = tokens.length; - if (len > 1) { - for (int i = 0; i < len; i++) { - String token = tokens[i]; - if (i < (len - 1)) { - path.append(token.toLowerCase(Locale.ENGLISH)).append('.'); - String[] subTokens = Arrays.copyOfRange(tokens, i + 1, len); - properties.add(path + Arrays.stream(subTokens).map(s -> s.toLowerCase(Locale.ENGLISH)).collect(Collectors.joining(""))); - } - } - } else { - return Collections.singletonList(property.toLowerCase(Locale.ENGLISH)); - } - return properties; + // environment variables are converted to lower case and dot separated + return Collections.singletonList(property.toLowerCase(Locale.ENGLISH).replace('_', '.')); default: - return Arrays.asList(property, property.toLowerCase(Locale.ENGLISH)); + return Collections.singletonList( + NameUtils.hyphenate(property, true) + ); } } diff --git a/inject/src/main/java/io/micronaut/inject/configuration/ConfigurationMetadataBuilder.java b/inject/src/main/java/io/micronaut/inject/configuration/ConfigurationMetadataBuilder.java index 73aacb44946..b813722c0ca 100644 --- a/inject/src/main/java/io/micronaut/inject/configuration/ConfigurationMetadataBuilder.java +++ b/inject/src/main/java/io/micronaut/inject/configuration/ConfigurationMetadataBuilder.java @@ -16,6 +16,7 @@ package io.micronaut.inject.configuration; import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.core.naming.NameUtils; import javax.annotation.Nullable; import javax.lang.model.element.TypeElement; @@ -67,7 +68,7 @@ public ConfigurationMetadata visitProperties(T type, String path = buildTypePath(type, type); ConfigurationMetadata configurationMetadata = new ConfigurationMetadata(); - configurationMetadata.name = path; + configurationMetadata.name = NameUtils.hyphenate(path, true); configurationMetadata.type = getTypeString(type); configurationMetadata.description = description; this.configurations.add(configurationMetadata); @@ -95,7 +96,7 @@ public PropertyMetadata visitProperty(T owningType, PropertyMetadata metadata = new PropertyMetadata(); metadata.declaringType = getTypeString(declaringType); metadata.name = name; - metadata.path = buildPropertyPath(owningType,declaringType, name); + metadata.path = NameUtils.hyphenate( buildPropertyPath(owningType,declaringType, name), true); metadata.type = propertyType; metadata.description = description; metadata.defaultValue = defaultValue; @@ -122,7 +123,7 @@ public PropertyMetadata visitProperty(String propertyType, PropertyMetadata metadata = new PropertyMetadata(); metadata.declaringType = last.type; metadata.name = name; - metadata.path = last.name + "." + name; + metadata.path = NameUtils.hyphenate( last.name + "." + name, true) ; metadata.type = propertyType; metadata.description = description; metadata.defaultValue = defaultValue; diff --git a/inject/src/test/groovy/io/micronaut/context/env/PropertySourcePropertyResolverSpec.groovy b/inject/src/test/groovy/io/micronaut/context/env/PropertySourcePropertyResolverSpec.groovy index 9793f5732b7..b7c903c17a9 100644 --- a/inject/src/test/groovy/io/micronaut/context/env/PropertySourcePropertyResolverSpec.groovy +++ b/inject/src/test/groovy/io/micronaut/context/env/PropertySourcePropertyResolverSpec.groovy @@ -26,8 +26,28 @@ class PropertySourcePropertyResolverSpec extends Specification { @Unroll - void "test resolve environment properties"() { + void "test property resolution rules for key #key"() { + given: + PropertySourcePropertyResolver resolver = new PropertySourcePropertyResolver( + PropertySource.of("test", [TWITTER_OAUTH2_ACCESS_TOKEN: 'xxx'], PropertySource.PropertyConvention.ENVIRONMENT_VARIABLE), + PropertySource.of("test", + ['camelCase.fooBar': 'xxx', + 'camelCase.URL' : "http://localhost"], + PropertySource.PropertyConvention.JAVA_PROPERTIES + ) + ) + expect: + resolver.containsProperty(key) + resolver.getProperty(key, Object).isPresent() + resolver.getProperty(key, String).get() == expected + + + where: + key | expected + 'twitter.oauth2.access.token' | 'xxx' + 'camel-case.foo-bar' | 'xxx' + 'camel-case.url' | 'http://localhost' } @Unroll @@ -46,10 +66,7 @@ class PropertySourcePropertyResolverSpec extends Specification { property | value | key | type | expected 'TWITTER_OAUTH2_ACCESS_TOKEN' | 'xxx' | 'twitter.oauth2-access-token' | String | 'xxx' 'TWITTER_OAUTH2_ACCESS_TOKEN' | 'xxx' | 'twitter.oauth2.access.token' | String | 'xxx' - 'TWITTER_OAUTH2_ACCESS_TOKEN' | 'xxx' | 'twitter.oauth2.accesstoken' | String | 'xxx' 'TWITTER_OAUTH2_ACCESS_TOKEN' | 'xxx' | 'twitter.oauth2.access-token' | String | 'xxx' - 'TWITTER_OAUTH2_ACCESS_TOKEN' | 'xxx' | 'twitter.OAuth2AccessToken' | String | 'xxx' - 'TWITTER_OAUTH2_ACCESS_TOKEN' | 'xxx' | 'twitter.oauth2accesstoken' | String | 'xxx' } diff --git a/inject/src/test/groovy/io/micronaut/context/env/yaml/YamlPropertySourceLoaderSpec.groovy b/inject/src/test/groovy/io/micronaut/context/env/yaml/YamlPropertySourceLoaderSpec.groovy index 7432e944e98..71256d92ca8 100644 --- a/inject/src/test/groovy/io/micronaut/context/env/yaml/YamlPropertySourceLoaderSpec.groovy +++ b/inject/src/test/groovy/io/micronaut/context/env/yaml/YamlPropertySourceLoaderSpec.groovy @@ -18,10 +18,6 @@ package io.micronaut.context.env.yaml import io.micronaut.context.env.DefaultEnvironment import io.micronaut.context.env.Environment import io.micronaut.context.env.PropertySourceLoader -import io.micronaut.context.env.DefaultEnvironment -import io.micronaut.context.env.Environment -import io.micronaut.context.env.PropertySource -import io.micronaut.context.env.PropertySourceLoader import io.micronaut.core.io.service.ServiceDefinition import io.micronaut.core.io.service.SoftServiceLoader import spock.lang.Specification @@ -79,8 +75,8 @@ dataSource: then: env.get("hibernate.cache.queries", Boolean).get() == false - env.get("dataSource.pooled", Boolean).get() == true - env.get("dataSource.password", String).get() == 'test' - env.get("dataSource.jmxExport", boolean).get() == true + env.get("data-source.pooled", Boolean).get() == true + env.get("data-source.password", String).get() == 'test' + env.get("data-source.jmx-export", boolean).get() == true } } diff --git a/management/src/main/java/io/micronaut/management/health/monitor/HealthMonitorTask.java b/management/src/main/java/io/micronaut/management/health/monitor/HealthMonitorTask.java index fd4a69ad55d..25d88ce14f8 100644 --- a/management/src/main/java/io/micronaut/management/health/monitor/HealthMonitorTask.java +++ b/management/src/main/java/io/micronaut/management/health/monitor/HealthMonitorTask.java @@ -67,7 +67,7 @@ public HealthMonitorTask(CurrentHealthStatus currentHealthStatus, HealthIndicato */ @Scheduled( fixedDelay = "${micronaut.health.monitor.interval:1m}", - initialDelay = "${micronaut.health.monitor.initialDelay:1m}") + initialDelay = "${micronaut.health.monitor.initial-delay:1m}") void monitor() { if (LOG.isDebugEnabled()) { LOG.debug("Starting health monitor check"); diff --git a/router/src/main/java/io/micronaut/web/router/DefaultRouteBuilder.java b/router/src/main/java/io/micronaut/web/router/DefaultRouteBuilder.java index 9088abff9d0..5960aeb25ab 100644 --- a/router/src/main/java/io/micronaut/web/router/DefaultRouteBuilder.java +++ b/router/src/main/java/io/micronaut/web/router/DefaultRouteBuilder.java @@ -125,7 +125,7 @@ public DefaultRouteBuilder(ExecutionHandleLocator executionHandleLocator, UriNam if (executionHandleLocator instanceof ApplicationContext) { ApplicationContext applicationContext = (ApplicationContext) executionHandleLocator; Environment environment = applicationContext.getEnvironment(); - defaultCharset = environment.get("micronaut.application.defaultCharset", Charset.class, StandardCharsets.UTF_8); + defaultCharset = environment.get("micronaut.application.default-charset", Charset.class, StandardCharsets.UTF_8); } else { defaultCharset = StandardCharsets.UTF_8; } diff --git a/runtime/src/main/java/io/micronaut/discovery/CompositeDiscoveryClient.java b/runtime/src/main/java/io/micronaut/discovery/CompositeDiscoveryClient.java index 5fda76acb75..4693bccbbb9 100644 --- a/runtime/src/main/java/io/micronaut/discovery/CompositeDiscoveryClient.java +++ b/runtime/src/main/java/io/micronaut/discovery/CompositeDiscoveryClient.java @@ -17,6 +17,7 @@ package io.micronaut.discovery; import io.micronaut.cache.CacheConfiguration; +import io.micronaut.core.naming.NameUtils; import io.micronaut.core.util.ArrayUtils; import io.reactivex.Flowable; import io.reactivex.Maybe; @@ -56,10 +57,12 @@ public String getDescription() { @Override public Flowable> getInstances(String serviceId) { + serviceId = NameUtils.hyphenate(serviceId); if (ArrayUtils.isEmpty(discoveryClients)) { return Flowable.just(Collections.emptyList()); } - Stream>> flowableStream = Arrays.stream(discoveryClients).map(client -> Flowable.fromPublisher(client.getInstances(serviceId))); + String finalServiceId = serviceId; + Stream>> flowableStream = Arrays.stream(discoveryClients).map(client -> Flowable.fromPublisher(client.getInstances(finalServiceId))); Maybe> reduced = Flowable.merge(flowableStream.collect(Collectors.toList())).reduce((instances, otherInstances) -> { instances.addAll(otherInstances); return instances; diff --git a/runtime/src/main/java/io/micronaut/discovery/config/ConfigurationClient.java b/runtime/src/main/java/io/micronaut/discovery/config/ConfigurationClient.java index e61a457592b..be51cd3ee00 100644 --- a/runtime/src/main/java/io/micronaut/discovery/config/ConfigurationClient.java +++ b/runtime/src/main/java/io/micronaut/discovery/config/ConfigurationClient.java @@ -32,7 +32,7 @@ public interface ConfigurationClient extends Described { /** * The prefix used to configure the config client. */ - String CONFIGURATION_PREFIX = "micronaut.configClient"; + String CONFIGURATION_PREFIX = "micronaut.config-client"; /** * The read timeout used when reading distributed configuration. @@ -42,7 +42,7 @@ public interface ConfigurationClient extends Described { /** * The read timeout used when reading distributed configuration. */ - String READ_TIMEOUT = CONFIGURATION_PREFIX + ".readTimeout"; + String READ_TIMEOUT = CONFIGURATION_PREFIX + ".read-timeout"; /** * Retrieves all of the {@link PropertySource} registrations for the given environment. diff --git a/runtime/src/main/java/io/micronaut/health/HeartbeatTask.java b/runtime/src/main/java/io/micronaut/health/HeartbeatTask.java index b38cbcfbefd..90453eb319a 100644 --- a/runtime/src/main/java/io/micronaut/health/HeartbeatTask.java +++ b/runtime/src/main/java/io/micronaut/health/HeartbeatTask.java @@ -60,7 +60,7 @@ public HeartbeatTask(ApplicationEventPublisher eventPublisher, HeartbeatConfigur /** * Publish the heartbeat event with current health status. */ - @Scheduled(fixedDelay = "${micronaut.heartbeat.interval:15s}", initialDelay = "${micronaut.heartbeat.initialDelay:5s}") + @Scheduled(fixedDelay = "${micronaut.heartbeat.interval:15s}", initialDelay = "${micronaut.heartbeat.initial-delay:5s}") public void pulsate() { ServiceInstance instance = eventReference.get(); if (instance != null) { diff --git a/runtime/src/main/java/io/micronaut/jackson/bind/MapToObjectConverter.java b/runtime/src/main/java/io/micronaut/jackson/bind/MapToObjectConverter.java index eda8bf8ab9e..22248c94edc 100644 --- a/runtime/src/main/java/io/micronaut/jackson/bind/MapToObjectConverter.java +++ b/runtime/src/main/java/io/micronaut/jackson/bind/MapToObjectConverter.java @@ -19,11 +19,15 @@ import io.micronaut.core.bind.BeanPropertyBinder; import io.micronaut.core.convert.ConversionContext; import io.micronaut.core.convert.TypeConverter; +import io.micronaut.core.naming.NameUtils; import io.micronaut.core.reflect.InstantiationUtils; import javax.inject.Singleton; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * A class that uses the {@link BeanPropertyBinder} to bind maps to {@link Object} instances. @@ -47,6 +51,17 @@ public MapToObjectConverter(BeanPropertyBinder beanPropertyBinder) { public Optional convert(Map map, Class targetType, ConversionContext context) { return InstantiationUtils .tryInstantiate(targetType) - .map(object -> beanPropertyBinder.bind(object, map)); + + .map(object -> + { + Map theMap = map; + Map bindMap = new LinkedHashMap(map.size()); + for (Map.Entry entry : theMap.entrySet()) { + Object key = entry.getKey(); + bindMap.put(NameUtils.decapitalize(NameUtils.dehyphenate(key.toString())), entry.getValue()); + } + return beanPropertyBinder.bind(object, bindMap); + } + ); } } diff --git a/runtime/src/main/java/io/micronaut/runtime/ApplicationConfiguration.java b/runtime/src/main/java/io/micronaut/runtime/ApplicationConfiguration.java index fe8ea2fc7f6..97077298786 100644 --- a/runtime/src/main/java/io/micronaut/runtime/ApplicationConfiguration.java +++ b/runtime/src/main/java/io/micronaut/runtime/ApplicationConfiguration.java @@ -18,6 +18,7 @@ import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.context.annotation.Primary; +import io.micronaut.core.naming.NameUtils; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -43,7 +44,7 @@ public class ApplicationConfiguration { /** * Property name for Micronaut default charset. */ - public static final String DEFAULT_CHARSET = PREFIX + ".defaultCharset"; + public static final String DEFAULT_CHARSET = PREFIX + ".default-charset"; /** * Property name for Micronaut application name. @@ -83,7 +84,9 @@ public Optional getName() { * @param name Set the application name */ public void setName(String name) { - this.name = name; + if(name != null) { + this.name = NameUtils.hyphenate(name); + } } /** diff --git a/runtime/src/test/groovy/io/micronaut/jackson/JacksonSetupSpec.groovy b/runtime/src/test/groovy/io/micronaut/jackson/JacksonSetupSpec.groovy index 258dda28133..b0565aa7a1b 100644 --- a/runtime/src/test/groovy/io/micronaut/jackson/JacksonSetupSpec.groovy +++ b/runtime/src/test/groovy/io/micronaut/jackson/JacksonSetupSpec.groovy @@ -15,14 +15,12 @@ */ package io.micronaut.jackson +import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import io.micronaut.context.ApplicationContext import io.micronaut.context.DefaultApplicationContext import io.micronaut.context.env.MapPropertySource -import io.micronaut.context.ApplicationContext -import io.micronaut.context.DefaultApplicationContext -import io.micronaut.context.env.MapPropertySource import io.micronaut.jackson.JacksonConfiguration import spock.lang.Specification @@ -52,7 +50,8 @@ class JacksonSetupSpec extends Specification { ApplicationContext applicationContext = new DefaultApplicationContext("test") applicationContext.environment.addPropertySource(MapPropertySource.of( 'jackson.dateFormat':'yyMMdd', - 'jackson.serialization.indentOutput':true + 'jackson.serialization.indentOutput':true, +// 'jackson.deserialization.UNWRAP_ROOT_VALUE': true )) applicationContext.start() @@ -61,6 +60,7 @@ class JacksonSetupSpec extends Specification { applicationContext.containsBean(JacksonConfiguration) applicationContext.getBean(JacksonConfiguration).dateFormat == 'yyMMdd' applicationContext.getBean(JacksonConfiguration).serializationSettings.get(SerializationFeature.INDENT_OUTPUT) +// applicationContext.getBean(JacksonConfiguration).deserializationSettings.get(DeserializationFeature.UNWRAP_ROOT_VALUE) applicationContext.getBean(ObjectMapper.class).valueToTree([foo:'bar']).get('foo').textValue() == 'bar' cleanup: diff --git a/runtime/src/test/groovy/io/micronaut/jackson/env/JsonPropertySourceLoaderSpec.groovy b/runtime/src/test/groovy/io/micronaut/jackson/env/JsonPropertySourceLoaderSpec.groovy index a984c5e49c6..ec12563b690 100644 --- a/runtime/src/test/groovy/io/micronaut/jackson/env/JsonPropertySourceLoaderSpec.groovy +++ b/runtime/src/test/groovy/io/micronaut/jackson/env/JsonPropertySourceLoaderSpec.groovy @@ -133,10 +133,10 @@ class JsonPropertySourceLoaderSpec extends Specification { then: env.get("hibernate.cache.queries", Boolean).get() == false - env.get("dataSource.pooled", Boolean).get() == true - env.get("dataSource.password", String).get() == 'test' - env.get("dataSource.jmxExport", boolean).get() == true - env.get("dataSource.something", List).get() == [1,2] + env.get("data-source.pooled", Boolean).get() == true + env.get("data-source.password", String).get() == 'test' + env.get("data-source.jmx-export", boolean).get() == true + env.get("data-source.something", List).get() == [1,2] diff --git a/spring/src/main/java/io/micronaut/spring/core/env/PropertyResolverAdapter.java b/spring/src/main/java/io/micronaut/spring/core/env/PropertyResolverAdapter.java index 9f483f725aa..04472ebe55c 100644 --- a/spring/src/main/java/io/micronaut/spring/core/env/PropertyResolverAdapter.java +++ b/spring/src/main/java/io/micronaut/spring/core/env/PropertyResolverAdapter.java @@ -17,6 +17,7 @@ package io.micronaut.spring.core.env; import io.micronaut.context.env.PropertyPlaceholderResolver; +import io.micronaut.core.naming.NameUtils; import io.micronaut.core.reflect.ClassUtils; import org.springframework.core.env.PropertyResolver; @@ -46,34 +47,34 @@ public PropertyResolverAdapter(io.micronaut.core.value.PropertyResolver property @Override public boolean containsProperty(String key) { - return propertyResolver.getProperty(key, String.class).isPresent(); + return propertyResolver.getProperty(NameUtils.hyphenate(key), String.class).isPresent(); } @Override public String getProperty(String key) { - return propertyResolver.getProperty(key, String.class).orElse(null); + return propertyResolver.getProperty(NameUtils.hyphenate(key), String.class).orElse(null); } @Override public String getProperty(String key, String defaultValue) { - return getProperty(key, String.class, null); + return getProperty(NameUtils.hyphenate(key), String.class, null); } @Override public T getProperty(String key, Class targetType) { - return getProperty(key, targetType, null); + return getProperty(NameUtils.hyphenate(key), targetType, null); } @Override public T getProperty(String key, Class targetType, T defaultValue) { - return propertyResolver.getProperty(key, targetType, defaultValue); + return propertyResolver.getProperty(NameUtils.hyphenate(key), targetType, defaultValue); } @Override public Class getPropertyAsClass(String key, Class targetType) { - Optional property = propertyResolver.getProperty(key, String.class); + Optional property = propertyResolver.getProperty(NameUtils.hyphenate(key), String.class); if (property.isPresent()) { - Optional aClass = ClassUtils.forName(key, Thread.currentThread().getContextClassLoader()); + Optional aClass = ClassUtils.forName(property.get(), Thread.currentThread().getContextClassLoader()); if (aClass.isPresent()) { return aClass.get(); } @@ -83,12 +84,12 @@ public Class getPropertyAsClass(String key, Class targetType) { @Override public String getRequiredProperty(String key) throws IllegalStateException { - return getRequiredProperty(key, String.class); + return getRequiredProperty(NameUtils.hyphenate(key), String.class); } @Override public T getRequiredProperty(String key, Class targetType) throws IllegalStateException { - T v = getProperty(key, targetType, null); + T v = getProperty(NameUtils.hyphenate(key), targetType, null); if (v == null) { throw new IllegalStateException("Property [" + key + "] not found"); } diff --git a/src/main/docs/guide/ioc/configurations.adoc b/src/main/docs/guide/ioc/configurations.adoc index a8ba5bd4f71..b018bad84ae 100644 --- a/src/main/docs/guide/ioc/configurations.adoc +++ b/src/main/docs/guide/ioc/configurations.adoc @@ -50,6 +50,6 @@ The link:{api}/io/micronaut/context/annotation/Requires.html[@Requires] annotati |`@Requires(sdk=Sdk.JAVA, value="1.8")` |Require a property with an optional value -|`@Requires(property='dataSource.url')` +|`@Requires(property='data-source.url')` |===