Skip to content

Commit

Permalink
Create ConfigurationPropertySource abstraction
Browse files Browse the repository at this point in the history
Add a new abstraction that represents a source for configuration
properties. The new source is similar to the `Environment` abstraction
provided by Spring Framework but follows a stricter set of rules.

The `ConfigurationPropertySource` provides a uniform view onto a source
and will help to move responsibility for accessing properties in a
"relaxed" way away from the caller.

The `ConfigurationPropertyName` class enforces strict naming rules
that callers must follow when accessing properties. Configuration
names are lowercase, dot separated and may contain dashes. In
addition "indexed" name elements may be defined by using square
brackets.

Mapping is provided to existing Spring PropertySources implemented with
the relaxed rules that users are used to. For example the configuration
property `server.local-host` can still be written in a property files
as `server.localHost` or in an environment variable as SERVER_LOCALHOST.

Closes spring-projectsgh-4910
  • Loading branch information
philwebb committed Apr 25, 2017
1 parent 70d0d39 commit 14b3289
Show file tree
Hide file tree
Showing 31 changed files with 3,950 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,8 +15,7 @@
*/

/**
* Support for external configuration binding via the {@code @ConfigurationProperties}
* annotation.
* Support for external configuration properties.
*
* @see org.springframework.boot.context.properties.ConfigurationProperties
* @see org.springframework.boot.context.properties.EnableConfigurationProperties
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2012-2017 the original author or 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 org.springframework.boot.context.properties.source;

import java.util.List;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
* A {@link ConfigurationPropertySource} supporting name aliases.
*
* @author Phillip Webb
* @author Madhura Bhave
*/
class AliasedConfigurationPropertySource implements ConfigurationPropertySource {

private final ConfigurationPropertySource source;

private final ConfigurationPropertyNameAliases aliases;

AliasedConfigurationPropertySource(ConfigurationPropertySource source,
ConfigurationPropertyNameAliases aliases) {
Assert.notNull(source, "Source must not be null");
Assert.notNull(aliases, "Aliases must not be null");
this.source = source;
this.aliases = aliases;
}

@Override
public Stream<ConfigurationPropertyName> stream() {
return StreamSupport.stream(this.source.spliterator(), false)
.flatMap(this::addAliases);
}

private Stream<ConfigurationPropertyName> addAliases(ConfigurationPropertyName name) {
Stream<ConfigurationPropertyName> names = Stream.of(name);
List<ConfigurationPropertyName> aliases = this.aliases.getAliases(name);
if (CollectionUtils.isEmpty(aliases)) {
return names;
}
return Stream.concat(names, aliases.stream());
}

@Override
public ConfigurationProperty getConfigurationProperty(
ConfigurationPropertyName name) {
Assert.notNull(name, "Name must not be null");
ConfigurationProperty result = this.source.getConfigurationProperty(name);
if (result == null) {
ConfigurationPropertyName aliasedName = this.aliases.getNameForAlias(name);
result = this.source.getConfigurationProperty(aliasedName);
}
return result;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright 2012-2017 the original author or 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 org.springframework.boot.context.properties.source;

import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginProvider;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
* A single configuration property obtained from a {@link ConfigurationPropertySource}
* consisting of a {@link #getName() name}, {@link #getValue() value} and optional
* {@link #getOrigin() origin}.
*
* @author Phillip Webb
* @author Madhura Bhave
* @since 2.0.0
*/
public final class ConfigurationProperty
implements OriginProvider, Comparable<ConfigurationProperty> {

private final ConfigurationPropertyName name;

private final Object value;

private final Origin origin;

public ConfigurationProperty(ConfigurationPropertyName name, Object value,
Origin origin) {
Assert.notNull(name, "Name must not be null");
Assert.notNull(value, "Value must not be null");
this.name = name;
this.value = value;
this.origin = origin;
}

public ConfigurationPropertyName getName() {
return this.name;
}

public Object getValue() {
return this.value;
}

@Override
public Origin getOrigin() {
return this.origin;
}

@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(this.name);
result = 31 * result + ObjectUtils.nullSafeHashCode(this.value);
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ConfigurationProperty other = (ConfigurationProperty) obj;
boolean result = true;
result = result && ObjectUtils.nullSafeEquals(this.name, other.name);
result = result && ObjectUtils.nullSafeEquals(this.value, other.value);
return result;
}

@Override
public String toString() {
return new ToStringCreator(this).append("name", this.name)
.append("value", this.value).append("origin", this.origin).toString();
}

@Override
public int compareTo(ConfigurationProperty other) {
return this.name.compareTo(other.name);
}

static ConfigurationProperty of(ConfigurationPropertyName name,
OriginTrackedValue value) {
if (value == null) {
return null;
}
return new ConfigurationProperty(name, value.getValue(), value.getOrigin());
}

static ConfigurationProperty of(ConfigurationPropertyName name, Object value,
Origin origin) {
if (value == null) {
return null;
}
return new ConfigurationProperty(name, value, origin);
}

}
Loading

0 comments on commit 14b3289

Please sign in to comment.