Restructor and improve Origin support

Move the `Origin` and related classes from `o.s.boot.env` to
`o.s.boot.orgin` and extend support. The concept of an origin can now
be used outside of just the Spring Environment abstraction.

Closes gh-9001
This commit is contained in:
Phillip Webb 2017-04-17 11:41:53 -07:00
parent b10e2f3a05
commit dbc7e938c8
21 changed files with 718 additions and 109 deletions

View File

@ -1,39 +0,0 @@
/*
* 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.env;
import org.springframework.core.env.PropertySource;
/**
* An additional interface that may be implemented by a {@link PropertySource} that can
* return origin information. For example a property source that's backed by a file may
* return origin information for line and column numbers.
*
* @author Phillip Webb
* @since 2.0.0
*/
public interface OriginCapablePropertySource {
/**
* Return the origin of the given property name or {@code null} if the origin cannot
* be determined.
* @param name the property name
* @return the origin of the property or {@code null}
*/
PropertyOrigin getPropertyOrigin(String name);
}

View File

@ -18,18 +18,21 @@ package org.springframework.boot.env;
import java.util.Map;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.core.env.MapPropertySource;
/**
* {@link OriginCapablePropertySource} backed by a {@link Map} containing
* {@link OriginTrackedValue OriginTrackedValues}.
* {@link OriginLookup} backed by a {@link Map} containing {@link OriginTrackedValue
* OriginTrackedValues}.
*
* @author Madhura Bhave
* @author Phillip Webb
* @see OriginTrackedValue
*/
class OriginTrackedMapPropertySource extends MapPropertySource
implements OriginCapablePropertySource {
implements OriginLookup<String> {
@SuppressWarnings({ "unchecked", "rawtypes" })
OriginTrackedMapPropertySource(String name, Map source) {
@ -46,7 +49,7 @@ class OriginTrackedMapPropertySource extends MapPropertySource
}
@Override
public PropertyOrigin getPropertyOrigin(String name) {
public Origin getOrigin(String name) {
Object value = super.getProperty(name);
if (value instanceof OriginTrackedValue) {
return ((OriginTrackedValue) value).getOrigin();

View File

@ -23,7 +23,10 @@ import java.io.LineNumberReader;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.boot.env.TextResourcePropertyOrigin.Location;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.boot.origin.TextResourceOrigin.Location;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
@ -129,7 +132,7 @@ class OriginTrackedPropertiesLoader {
buffer.append(reader.getCharacter());
reader.read();
}
PropertyOrigin origin = new TextResourcePropertyOrigin(this.resource, location);
Origin origin = new TextResourceOrigin(this.resource, location);
return OriginTrackedValue.of(buffer.toString().trim(), origin);
}

View File

@ -37,7 +37,10 @@ import org.yaml.snakeyaml.representer.Representer;
import org.yaml.snakeyaml.resolver.Resolver;
import org.springframework.beans.factory.config.YamlProcessor;
import org.springframework.boot.env.TextResourcePropertyOrigin.Location;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.boot.origin.TextResourceOrigin.Location;
import org.springframework.boot.yaml.SpringProfileDocumentMatcher;
import org.springframework.core.io.Resource;
@ -106,14 +109,14 @@ class OriginTrackedYamlLoader extends YamlProcessor {
}
private Object constructTrackedObject(Node node, Object value) {
PropertyOrigin origin = getOrigin(node);
Origin origin = getOrigin(node);
return OriginTrackedValue.of(value, origin);
}
private PropertyOrigin getOrigin(Node node) {
private Origin getOrigin(Node node) {
Mark mark = node.getStartMark();
Location location = new Location(mark.getLine(), mark.getColumn());
return new TextResourcePropertyOrigin(OriginTrackedYamlLoader.this.resource,
return new TextResourceOrigin(OriginTrackedYamlLoader.this.resource,
location);
}

View File

@ -33,8 +33,8 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Utility that can be used update {@link MutablePropertySources} using
* {@link PropertySourceLoader}s.
* Utility that can be used to update {@link MutablePropertySources} using
* {@link PropertySourceLoader PropertySourceLoaders}.
*
* @author Phillip Webb
*/

View File

@ -0,0 +1,56 @@
/*
* 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.origin;
import java.io.File;
/**
* Interface that uniquely represents the origin of an item. For example, a item loaded
* from a {@link File} may have an origin made up of the file name along with line/column
* numbers.
* <p>
* Implementations must provide sensible {@code hashCode()}, {@code equals(...)} and
* {@code #toString()} implementations.
*
* @author Madhura Bhave
* @author Phillip Webb
* @since 2.0.0
* @see OriginProvider
*/
public interface Origin {
/**
* Find the {@link Origin} that an object originated from. Checks if the source object
* is a {@link OriginProvider} and also searches exception stacks.
* @param source the source object or {@code null}
* @return an optional {@link Origin}
*/
static Origin from(Object source) {
if (source instanceof Origin) {
return (Origin) source;
}
Origin origin = null;
if (source != null && source instanceof OriginProvider) {
origin = ((OriginProvider) source).getOrigin();
}
if (origin == null && source != null && source instanceof Throwable) {
return from(((Throwable) source).getCause());
}
return origin;
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.origin;
/**
* An interface that may be implemented by an object that can lookup {@link Origin}
* information from a given key. Can be used to add origin support to existing classes.
*
* @param <K> The lookup key type
* @author Phillip Webb
* @since 2.0.0
*/
public interface OriginLookup<K> {
/**
* Return the origin of the given key or {@code null} if the origin cannot be
* determined.
* @param key the key to lookup
* @return the origin of the key or {@code null}
*/
Origin getOrigin(K key);
/**
* Attempt to lookup the origin from the given source. If the source is not a
* {@link OriginLookup} or if an exception occurs during lookup then {@code null} is
* returned.
* @param source the source object
* @param key the key to lookup
* @param <K> the key type
* @return an {@link Origin} or {@code null}
*/
@SuppressWarnings("unchecked")
static <K> Origin getOrigin(Object source, K key) {
if (!(source instanceof OriginLookup)) {
return null;
}
try {
return ((OriginLookup<K>) source).getOrigin(key);
}
catch (Throwable ex) {
return null;
}
}
}

View File

@ -14,22 +14,21 @@
* limitations under the License.
*/
package org.springframework.boot.env;
import java.io.File;
package org.springframework.boot.origin;
/**
* Interface that uniquely represents the origin of a property. For example, a property
* loaded from a {@link File} may have an origin made up of the file name along with
* line/column numbers.
* <p>
* Implementations must provide sensible {@code hashCode()}, {@code equals(...)} and
* {@code #toString()} implementations.
* Interface to provide access to the origin of an item.
*
* @author Madhura Bhave
* @author Phillip Webb
* @since 2.0.0
* @see Origin
*/
public interface PropertyOrigin {
public interface OriginProvider {
/**
* Return the source origin or {@code null} if the origin is not known.
* @return the origin or {@code null}
*/
Origin getOrigin();
}

View File

@ -14,41 +14,51 @@
* limitations under the License.
*/
package org.springframework.boot.env;
package org.springframework.boot.origin;
import org.springframework.util.ObjectUtils;
/**
* Wrapper class for an Object {@code value} and {@link PropertyOrigin origin}.
* An wrapper for a {@link Object} value and {@link Origin}.
*
* @author Madhura Bhave
* @see OriginTrackedMapPropertySource
* @author Phillip Webb
* @since 2.0.0
* @see #of(Object)
* @see #of(Object, Origin)
*/
class OriginTrackedValue {
public class OriginTrackedValue implements OriginProvider {
private final Object value;
private final PropertyOrigin origin;
private final Origin origin;
OriginTrackedValue(Object value, PropertyOrigin origin) {
private OriginTrackedValue(Object value, Origin origin) {
this.value = value;
this.origin = origin;
}
/**
* Return the tracked value.
* @return the tracked value
*/
public Object getValue() {
return this.value;
}
public PropertyOrigin getOrigin() {
@Override
public Origin getOrigin() {
return this.origin;
}
@Override
public String toString() {
return this.value.toString();
return (this.value == null ? null : this.value.toString());
}
@Override
public int hashCode() {
return this.value.hashCode();
return ObjectUtils.nullSafeHashCode(this.value);
}
@Override
@ -56,7 +66,11 @@ class OriginTrackedValue {
if (obj == null || obj.getClass() != getClass()) {
return false;
}
return this.value.equals(((OriginTrackedValue) obj).value);
return ObjectUtils.nullSafeEquals(this.value, ((OriginTrackedValue) obj).value);
}
public static OriginTrackedValue of(Object value) {
return of(value, null);
}
/**
@ -65,10 +79,10 @@ class OriginTrackedValue {
* the resulting {@link OriginTrackedValue}.
* @param value the source value
* @param origin the origin
* @return an {@link OriginTrackedValue} or {@code null} if the source value was
* @return a {@link OriginTrackedValue} or {@code null} if the source value was
* {@code null}.
*/
public static OriginTrackedValue of(Object value, PropertyOrigin origin) {
public static OriginTrackedValue of(Object value, Origin origin) {
if (value == null) {
return null;
}
@ -84,7 +98,7 @@ class OriginTrackedValue {
private static class OriginTrackedCharSequence extends OriginTrackedValue
implements CharSequence {
OriginTrackedCharSequence(CharSequence value, PropertyOrigin origin) {
OriginTrackedCharSequence(CharSequence value, Origin origin) {
super(value, origin);
}

View File

@ -0,0 +1,81 @@
/*
* 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.origin;
import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert;
/**
* {@link Origin} from a {@link PropertySource}.
*
* @author Phillip Webb
* @since 2.0.0
*/
public class PropertySourceOrigin implements Origin {
private final PropertySource<?> propertySource;
private final String propertyName;
/**
* Create a new {@link PropertySourceOrigin} instance.
* @param propertySource the origin property source
* @param propertyName the origin property name
*/
public PropertySourceOrigin(PropertySource<?> propertySource, String propertyName) {
Assert.notNull(propertySource, "PropertySource must not be null");
Assert.hasLength(propertyName, "PropertyName must not be empty");
this.propertySource = propertySource;
this.propertyName = propertyName;
}
/**
* Return the origin {@link PropertySource}.
* @return the origin property source
*/
public PropertySource<?> getPropertySource() {
return this.propertySource;
}
/**
* Return the origin property name.
* @return the origin property name
*/
public String getPropertyName() {
return this.propertyName;
}
@Override
public String toString() {
return "\"" + this.propertyName + "\" from property source \""
+ this.propertySource.getName() + "\"";
}
/**
* Get a {@link Origin} for the given {@link PropertySource} and {@code propertyName}.
* Will either return an {@link OriginLookup} result or a
* {@link PropertySourceOrigin}.
* @param propertySource the origin property source
* @param name the property name
* @return the property origin
*/
public static Origin get(PropertySource<?> propertySource, String name) {
Origin origin = OriginLookup.getOrigin(propertySource, name);
return (origin != null ? origin : new PropertySourceOrigin(propertySource, name));
}
}

View File

@ -14,26 +14,26 @@
* limitations under the License.
*/
package org.springframework.boot.env;
package org.springframework.boot.origin;
import org.springframework.core.io.Resource;
import org.springframework.util.ObjectUtils;
/**
* {@link PropertyOrigin} for an item loaded from a text resource. Provides access to the
* {@link Origin} for an item loaded from a text resource. Provides access to the
* original {@link Resource} that loaded the text and a {@link Location} within it.
*
* @author Madhura Bhave
* @author Phillip Webb
* @since 2.0.0
*/
public class TextResourcePropertyOrigin implements PropertyOrigin {
public class TextResourceOrigin implements Origin {
private final Resource resource;
private final Location location;
public TextResourcePropertyOrigin(Resource resource, Location location) {
public TextResourceOrigin(Resource resource, Location location) {
this.resource = resource;
this.location = location;
}
@ -70,8 +70,8 @@ public class TextResourcePropertyOrigin implements PropertyOrigin {
if (obj == null) {
return false;
}
if (obj instanceof TextResourcePropertyOrigin) {
TextResourcePropertyOrigin other = (TextResourcePropertyOrigin) obj;
if (obj instanceof TextResourceOrigin) {
TextResourceOrigin other = (TextResourceOrigin) obj;
boolean result = true;
result = result && ObjectUtils.nullSafeEquals(this.resource, other.resource);
result = result && ObjectUtils.nullSafeEquals(this.location, other.location);

View File

@ -0,0 +1,21 @@
/*
* 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.
*/
/**
* Support for item origin tracking.
* @see org.springframework.boot.origin.Origin
*/
package org.springframework.boot.origin;

View File

@ -21,6 +21,9 @@ import java.util.Map;
import org.junit.Test;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginTrackedValue;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@ -37,7 +40,7 @@ public class OriginTrackedMapPropertySourceTests {
private OriginTrackedMapPropertySource source = new OriginTrackedMapPropertySource(
"test", this.map);
private PropertyOrigin origin = mock(PropertyOrigin.class);
private Origin origin = mock(Origin.class);
@Test
public void getPropertyWhenMissingShouldReturnNull() throws Exception {
@ -52,25 +55,25 @@ public class OriginTrackedMapPropertySourceTests {
@Test
public void getPropertyWhenTrackedShouldReturnValue() throws Exception {
this.map.put("test", new OriginTrackedValue("foo", this.origin));
this.map.put("test", OriginTrackedValue.of("foo", this.origin));
assertThat(this.source.getProperty("test")).isEqualTo("foo");
}
@Test
public void getPropertyOriginWhenMissingShouldReturnNull() throws Exception {
assertThat(this.source.getPropertyOrigin("test")).isNull();
assertThat(this.source.getOrigin("test")).isNull();
}
@Test
public void getPropertyOriginWhenNonTrackedShouldReturnNull() throws Exception {
this.map.put("test", "foo");
assertThat(this.source.getPropertyOrigin("test")).isNull();
assertThat(this.source.getOrigin("test")).isNull();
}
@Test
public void getPropertyOriginWhenTrackedShouldReturnOrigin() throws Exception {
this.map.put("test", new OriginTrackedValue("foo", this.origin));
assertThat(this.source.getPropertyOrigin("test")).isEqualTo(this.origin);
this.map.put("test", OriginTrackedValue.of("foo", this.origin));
assertThat(this.source.getOrigin("test")).isEqualTo(this.origin);
}
}

View File

@ -22,6 +22,8 @@ import java.util.Properties;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
@ -234,7 +236,8 @@ public class OriginTrackedPropertiesLoaderTests {
if (value == null) {
return null;
}
return ((TextResourcePropertyOrigin) value.getOrigin()).getLocation().toString();
return ((TextResourceOrigin) value.getOrigin()).getLocation()
.toString();
}
}

View File

@ -21,6 +21,8 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.origin.OriginTrackedValue;
import org.springframework.boot.origin.TextResourceOrigin;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@ -120,7 +122,8 @@ public class OriginTrackedYamlLoaderTests {
}
private String getLocation(OriginTrackedValue value) {
return ((TextResourcePropertyOrigin) value.getOrigin()).getLocation().toString();
return ((TextResourceOrigin) value.getOrigin()).getLocation()
.toString();
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.origin;
import org.springframework.util.Assert;
/**
* Mock {@link Origin} implementation used for testing.
*
* @author Phillip Webb
*/
public final class MockOrigin implements Origin {
private final String value;
private MockOrigin(String value) {
Assert.notNull(value, "Value must not be null");
this.value = value;
}
@Override
public int hashCode() {
return this.value.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return this.value.equals(((MockOrigin) obj).value);
}
@Override
public String toString() {
return this.value;
}
public static Origin of(String value) {
return (value == null ? null : new MockOrigin(value));
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.origin;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link OriginLookup}.
*
* @author Phillip Webb
*/
public class OriginLookupTests {
@Test
public void getOriginWhenSourceIsNullShouldReturnNull() throws Exception {
assertThat(OriginLookup.getOrigin(null, "foo")).isNull();
}
@Test
public void getOriginWhenSourceIsNotLookupShouldReturnLookupOrigin()
throws Exception {
Object source = new Object();
assertThat(OriginLookup.getOrigin(source, "foo")).isNull();
}
@Test
@SuppressWarnings("unchecked")
public void getOriginWhenSourceIsLookupShouldReturnLookupOrigin() throws Exception {
OriginLookup<String> source = mock(OriginLookup.class);
Origin origin = MockOrigin.of("bar");
given(source.getOrigin("foo")).willReturn(origin);
assertThat(OriginLookup.getOrigin(source, "foo")).isEqualTo(origin);
}
@Test
@SuppressWarnings("unchecked")
public void getOriginWhenSourceLookupThrowsAndErrorShouldReturnNull()
throws Exception {
OriginLookup<String> source = mock(OriginLookup.class);
willThrow(RuntimeException.class).given(source).getOrigin("foo");
assertThat(OriginLookup.getOrigin(source, "foo")).isNull();
}
}

View File

@ -0,0 +1,90 @@
/*
* 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.origin;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link Origin}.
*
* @author Phillip Webb
*/
public class OriginTests {
@Test
public void fromWhenSourceIsNullShouldReturnNull() throws Exception {
assertThat(Origin.from(null)).isNull();
}
@Test
public void fromWhenSourceIsRegularObjectShouldReturnNull() throws Exception {
Object source = new Object();
assertThat(Origin.from(source)).isNull();
}
@Test
public void fromWhenSourceIsOriginShouldReturnSource() throws Exception {
Origin origin = mock(Origin.class);
assertThat(Origin.from(origin)).isEqualTo(origin);
}
@Test
public void fromWhenSourceIsOriginProviderShouldReturnProvidedOrigin()
throws Exception {
Origin origin = mock(Origin.class);
OriginProvider originProvider = mock(OriginProvider.class);
given(originProvider.getOrigin()).willReturn(origin);
assertThat(Origin.from(origin)).isEqualTo(origin);
}
@Test
public void fromWhenSourceIsThrowableShouldUseCause() throws Exception {
Origin origin = mock(Origin.class);
Exception exception = new RuntimeException(new TestException(origin, null));
assertThat(Origin.from(exception)).isEqualTo(origin);
}
@Test
public void fromWhenSourceIsThrowableAndOriginProviderThatReturnsNullShouldUseCause()
throws Exception {
Origin origin = mock(Origin.class);
Exception exception = new TestException(null, new TestException(origin, null));
assertThat(Origin.from(exception)).isEqualTo(origin);
}
private static class TestException extends RuntimeException
implements OriginProvider {
private final Origin origin;
TestException(Origin origin, Throwable cause) {
super(cause);
this.origin = origin;
}
@Override
public Origin getOrigin() {
return this.origin;
}
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.origin;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link OriginTrackedValue}.
*
* @author Phillip Webb
*/
public class OriginTrackedValueTests {
@Test
public void getValueShouldReturnValue() throws Exception {
Object value = new Object();
assertThat(OriginTrackedValue.of(value).getValue()).isEqualTo(value);
}
@Test
public void getOriginShouldReturnOrigin() throws Exception {
Object value = new Object();
Origin origin = mock(Origin.class);
assertThat(OriginTrackedValue.of(value, origin).getOrigin()).isEqualTo(origin);
}
@Test
public void toStringShouldReturnValueToString() throws Exception {
Object value = new Object();
assertThat(OriginTrackedValue.of(value).toString()).isEqualTo(value.toString());
}
@Test
public void hashCodeAndEqualsShouldIgnoreOrigin() throws Exception {
Object value1 = new Object();
OriginTrackedValue tracked1 = OriginTrackedValue.of(value1);
OriginTrackedValue tracked2 = OriginTrackedValue.of(value1, mock(Origin.class));
OriginTrackedValue tracked3 = OriginTrackedValue.of(new Object());
assertThat(tracked1.hashCode()).isEqualTo(tracked2.hashCode());
assertThat(tracked1).isEqualTo(tracked1).isEqualTo(tracked2)
.isNotEqualTo(tracked3);
}
@Test
public void ofWhenValueIsNullShouldReturnNull() throws Exception {
assertThat(OriginTrackedValue.of(null)).isNull();
assertThat(OriginTrackedValue.of(null, mock(Origin.class))).isNull();
}
@Test
public void ofWhenValueIsCharSequenceShouldReturnCharSequence() throws Exception {
String value = "foo";
OriginTrackedValue tracked = OriginTrackedValue.of(value);
assertThat(tracked).isInstanceOf(CharSequence.class);
CharSequence charSequence = (CharSequence) tracked;
assertThat(charSequence.length()).isEqualTo(value.length());
assertThat(charSequence.charAt(0)).isEqualTo(value.charAt(0));
assertThat(charSequence.subSequence(0, 1)).isEqualTo(value.subSequence(0, 1));
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.origin;
import java.util.HashMap;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.withSettings;
/**
* Tests for {@link PropertySourceOrigin}.
*
* @author Phillip Webb
*/
public class PropertySourceOriginTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void createWhenPropertySourceIsNullShouldThrowException() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("PropertySource must not be null");
new PropertySourceOrigin(null, "name");
}
@Test
public void createWhenPropertyNameIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("PropertyName must not be empty");
new PropertySourceOrigin(mock(PropertySource.class), null);
}
@Test
public void createWhenPropertyNameIsEmptyShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("PropertyName must not be empty");
new PropertySourceOrigin(mock(PropertySource.class), "");
}
@Test
public void getPropertySourceShouldReturnPropertySource() throws Exception {
MapPropertySource propertySource = new MapPropertySource("test", new HashMap<>());
PropertySourceOrigin origin = new PropertySourceOrigin(propertySource, "foo");
assertThat(origin.getPropertySource()).isEqualTo(propertySource);
}
@Test
public void getPropertyNameShouldReturnPropertyName() throws Exception {
MapPropertySource propertySource = new MapPropertySource("test", new HashMap<>());
PropertySourceOrigin origin = new PropertySourceOrigin(propertySource, "foo");
assertThat(origin.getPropertyName()).isEqualTo("foo");
}
@Test
public void toStringShouldShowDetails() throws Exception {
MapPropertySource propertySource = new MapPropertySource("test", new HashMap<>());
PropertySourceOrigin origin = new PropertySourceOrigin(propertySource, "foo");
assertThat(origin.toString()).isEqualTo("\"foo\" from property source \"test\"");
}
@Test
@SuppressWarnings("unchecked")
public void getWhenPropertySourceSupportsOriginLookupShouldReturnOrigin()
throws Exception {
Origin origin = mock(Origin.class);
PropertySource<?> propertySource = mock(PropertySource.class,
withSettings().extraInterfaces(OriginLookup.class));
OriginLookup<String> originCapablePropertySource = (OriginLookup<String>) propertySource;
given(originCapablePropertySource.getOrigin("foo")).willReturn(origin);
assertThat(PropertySourceOrigin.get(propertySource, "foo")).isSameAs(origin);
}
@Test
public void getWhenPropertySourceSupportsOriginLookupButNoOriginShouldWrap()
throws Exception {
PropertySource<?> propertySource = mock(PropertySource.class,
withSettings().extraInterfaces(OriginLookup.class));
assertThat(PropertySourceOrigin.get(propertySource, "foo"))
.isInstanceOf(PropertySourceOrigin.class);
}
@Test
public void getWhenPropertySourceIsNotOriginAwareShouldWrap() throws Exception {
MapPropertySource propertySource = new MapPropertySource("test", new HashMap<>());
PropertySourceOrigin origin = new PropertySourceOrigin(propertySource, "foo");
assertThat(origin.getPropertySource()).isEqualTo(propertySource);
assertThat(origin.getPropertyName()).isEqualTo("foo");
}
}

View File

@ -14,47 +14,45 @@
* limitations under the License.
*/
package org.springframework.boot.env;
package org.springframework.boot.origin;
import org.junit.Test;
import org.springframework.boot.env.TextResourcePropertyOrigin.Location;
import org.springframework.boot.origin.TextResourceOrigin.Location;
import org.springframework.core.io.ClassPathResource;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link TextResourcePropertyOrigin}.
* Tests for {@link TextResourceOrigin}.
*
* @author Phillip Webb
*/
public class TextResourcePropertyOriginTests {
public class TextResourceOriginTests {
@Test
public void createWithNullResourceShouldSetNullResource() throws Exception {
TextResourcePropertyOrigin origin = new TextResourcePropertyOrigin(null, null);
TextResourceOrigin origin = new TextResourceOrigin(null, null);
assertThat(origin.getResource()).isNull();
}
@Test
public void createWithNullLocationShouldSetNullLocation() throws Exception {
TextResourcePropertyOrigin origin = new TextResourcePropertyOrigin(null, null);
TextResourceOrigin origin = new TextResourceOrigin(null, null);
assertThat(origin.getLocation()).isNull();
}
@Test
public void getResourceShouldReturnResource() throws Exception {
ClassPathResource resource = new ClassPathResource("foo.txt");
TextResourcePropertyOrigin origin = new TextResourcePropertyOrigin(resource,
null);
TextResourceOrigin origin = new TextResourceOrigin(resource, null);
assertThat(origin.getResource()).isEqualTo(resource);
}
@Test
public void getLocationShouldReturnLocation() throws Exception {
Location location = new Location(1, 2);
TextResourcePropertyOrigin origin = new TextResourcePropertyOrigin(null,
location);
TextResourceOrigin origin = new TextResourceOrigin(null, location);
assertThat(origin.getLocation()).isEqualTo(location);
}
@ -81,24 +79,21 @@ public class TextResourcePropertyOriginTests {
public void toStringShouldReturnNiceString() throws Exception {
ClassPathResource resource = new ClassPathResource("foo.txt");
Location location = new Location(1, 2);
TextResourcePropertyOrigin origin = new TextResourcePropertyOrigin(resource,
location);
TextResourceOrigin origin = new TextResourceOrigin(resource, location);
assertThat(origin.toString()).isEqualTo("class path resource [foo.txt]:2:3");
}
@Test
public void toStringWhenResourceIsNullShouldReturnNiceString() throws Exception {
Location location = new Location(1, 2);
TextResourcePropertyOrigin origin = new TextResourcePropertyOrigin(null,
location);
TextResourceOrigin origin = new TextResourceOrigin(null, location);
assertThat(origin.toString()).isEqualTo("unknown resource [?]:2:3");
}
@Test
public void toStringWhenLocationIsNullShouldReturnNiceString() throws Exception {
ClassPathResource resource = new ClassPathResource("foo.txt");
TextResourcePropertyOrigin origin = new TextResourcePropertyOrigin(resource,
null);
TextResourceOrigin origin = new TextResourceOrigin(resource, null);
assertThat(origin.toString()).isEqualTo("class path resource [foo.txt]");
}
@ -117,13 +112,13 @@ public class TextResourcePropertyOriginTests {
@Test
public void equalsAndHashCodeShouldResourceAndLocation() throws Exception {
TextResourcePropertyOrigin origin1 = new TextResourcePropertyOrigin(
TextResourceOrigin origin1 = new TextResourceOrigin(
new ClassPathResource("foo.txt"), new Location(1, 2));
TextResourcePropertyOrigin origin2 = new TextResourcePropertyOrigin(
TextResourceOrigin origin2 = new TextResourceOrigin(
new ClassPathResource("foo.txt"), new Location(1, 2));
TextResourcePropertyOrigin origin3 = new TextResourcePropertyOrigin(
TextResourceOrigin origin3 = new TextResourceOrigin(
new ClassPathResource("foo.txt"), new Location(2, 2));
TextResourcePropertyOrigin origin4 = new TextResourcePropertyOrigin(
TextResourceOrigin origin4 = new TextResourceOrigin(
new ClassPathResource("foo2.txt"), new Location(1, 2));
assertThat(origin1.hashCode()).isEqualTo(origin1.hashCode());
assertThat(origin1.hashCode()).isEqualTo(origin2.hashCode());