diff --git a/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java b/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java index 9ba7187687..3777ed0557 100644 --- a/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java +++ b/spring-beans/src/main/java/org/springframework/beans/MutablePropertyValues.java @@ -18,16 +18,21 @@ package org.springframework.beans; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** - * Default implementation of the {@link PropertyValues} interface. + * The default implementation of the {@link PropertyValues} interface. * Allows simple manipulation of properties, and provides constructors * to support deep copy and construction from a Map. * @@ -244,6 +249,21 @@ public class MutablePropertyValues implements PropertyValues, Serializable { } + @Override + public Iterator iterator() { + return Collections.unmodifiableList(this.propertyValueList).iterator(); + } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(this.propertyValueList, 0); + } + + @Override + public Stream stream() { + return this.propertyValueList.stream(); + } + @Override public PropertyValue[] getPropertyValues() { return this.propertyValueList.toArray(new PropertyValue[0]); diff --git a/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java b/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java index 8e0abb1427..94e3031ff6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java +++ b/spring-beans/src/main/java/org/springframework/beans/PropertyValues.java @@ -16,6 +16,13 @@ package org.springframework.beans; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + import org.springframework.lang.Nullable; /** @@ -27,7 +34,33 @@ import org.springframework.lang.Nullable; * @since 13 May 2001 * @see PropertyValue */ -public interface PropertyValues { +public interface PropertyValues extends Iterable { + + /** + * Return an {@link Iterator} over the property values. + * @since 5.1 + */ + @Override + default Iterator iterator() { + return Arrays.asList(getPropertyValues()).iterator(); + } + + /** + * Return a {@link Spliterator} over the property values. + * @since 5.1 + */ + @Override + default Spliterator spliterator() { + return Spliterators.spliterator(getPropertyValues(), 0); + } + + /** + * Return a sequential {@link Stream} containing the property values. + * @since 5.1 + */ + default Stream stream() { + return StreamSupport.stream(spliterator(), false); + } /** * Return an array of the PropertyValue objects held in this object. diff --git a/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java b/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java index 4a657400c2..5416624420 100644 --- a/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/AbstractPropertyValuesTests.java @@ -30,7 +30,7 @@ public abstract class AbstractPropertyValuesTests { /** * Must contain: forname=Tony surname=Blair age=50 */ - protected void doTestTony(PropertyValues pvs) throws Exception { + protected void doTestTony(PropertyValues pvs) { assertTrue("Contains 3", pvs.getPropertyValues().length == 3); assertTrue("Contains forname", pvs.contains("forname")); assertTrue("Contains surname", pvs.contains("surname")); diff --git a/spring-beans/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java b/spring-beans/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java index 54db575086..b01d7829dc 100644 --- a/spring-beans/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/MutablePropertyValuesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2018 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. @@ -16,8 +16,11 @@ package org.springframework.beans; +import java.util.Iterator; + import org.junit.Test; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; /** @@ -25,11 +28,12 @@ import static org.junit.Assert.*; * * @author Rod Johnson * @author Chris Beams + * @author Juergen Hoeller */ public class MutablePropertyValuesTests extends AbstractPropertyValuesTests { @Test - public void testValid() throws Exception { + public void testValid() { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("forname", "Tony")); pvs.addPropertyValue(new PropertyValue("surname", "Blair")); @@ -44,7 +48,7 @@ public class MutablePropertyValuesTests extends AbstractPropertyValuesTests { } @Test - public void testAddOrOverride() throws Exception { + public void testAddOrOverride() { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("forname", "Tony")); pvs.addPropertyValue(new PropertyValue("surname", "Blair")); @@ -59,7 +63,7 @@ public class MutablePropertyValuesTests extends AbstractPropertyValuesTests { } @Test - public void testChangesOnEquals() throws Exception { + public void testChangesOnEquals() { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("forname", "Tony")); pvs.addPropertyValue(new PropertyValue("surname", "Blair")); @@ -70,7 +74,7 @@ public class MutablePropertyValuesTests extends AbstractPropertyValuesTests { } @Test - public void testChangeOfOneField() throws Exception { + public void testChangeOfOneField() { MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValue(new PropertyValue("forname", "Tony")); pvs.addPropertyValue(new PropertyValue("surname", "Blair")); @@ -103,4 +107,50 @@ public class MutablePropertyValuesTests extends AbstractPropertyValuesTests { assertTrue("new value is bar", fn.getValue().equals("bar")); } + @Test + public void iteratorContainsPropertyValue() { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.add("foo", "bar"); + + Iterator it = pvs.iterator(); + assertTrue(it.hasNext()); + PropertyValue pv = it.next(); + assertEquals("foo", pv.getName()); + assertEquals("bar", pv.getValue()); + + try { + it.remove(); + fail("Should have thrown UnsupportedOperationException"); + } + catch (UnsupportedOperationException ex) { + // expected + } + assertFalse(it.hasNext()); + } + + @Test + public void iteratorIsEmptyForEmptyValues() { + MutablePropertyValues pvs = new MutablePropertyValues(); + Iterator it = pvs.iterator(); + assertFalse(it.hasNext()); + } + + @Test + public void streamContainsPropertyValue() { + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.add("foo", "bar"); + + assertThat(pvs.stream(), notNullValue()); + assertThat(pvs.stream().count(), is(1L)); + assertThat(pvs.stream().anyMatch(pv -> "foo".equals(pv.getName()) && "bar".equals(pv.getValue())), is(true)); + assertThat(pvs.stream().anyMatch(pv -> "bar".equals(pv.getName()) && "foo".equals(pv.getValue())), is(false)); + } + + @Test + public void streamIsEmptyForEmptyValues() { + MutablePropertyValues pvs = new MutablePropertyValues(); + assertThat(pvs.stream(), notNullValue()); + assertThat(pvs.stream().count(), is(0L)); + } + } diff --git a/spring-core/src/main/java/org/springframework/core/env/MutablePropertySources.java b/spring-core/src/main/java/org/springframework/core/env/MutablePropertySources.java index 5a32be44c2..4adf1e50b7 100644 --- a/spring-core/src/main/java/org/springframework/core/env/MutablePropertySources.java +++ b/spring-core/src/main/java/org/springframework/core/env/MutablePropertySources.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -18,7 +18,10 @@ package org.springframework.core.env; import java.util.Iterator; import java.util.List; +import java.util.Spliterator; +import java.util.Spliterators; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -26,7 +29,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.lang.Nullable; /** - * Default implementation of the {@link PropertySources} interface. + * The default implementation of the {@link PropertySources} interface. * Allows manipulation of contained property sources and provides a constructor * for copying an existing {@code PropertySources} instance. * @@ -73,6 +76,21 @@ public class MutablePropertySources implements PropertySources { } + @Override + public Iterator> iterator() { + return this.propertySourceList.iterator(); + } + + @Override + public Spliterator> spliterator() { + return Spliterators.spliterator(this.propertySourceList, 0); + } + + @Override + public Stream> stream() { + return this.propertySourceList.stream(); + } + @Override public boolean contains(String name) { return this.propertySourceList.contains(PropertySource.named(name)); @@ -85,10 +103,6 @@ public class MutablePropertySources implements PropertySources { return (index != -1 ? this.propertySourceList.get(index) : null); } - @Override - public Iterator> iterator() { - return this.propertySourceList.iterator(); - } /** * Add the given property source object with highest precedence. diff --git a/spring-core/src/main/java/org/springframework/core/env/PropertySources.java b/spring-core/src/main/java/org/springframework/core/env/PropertySources.java index b4b0d7432e..812963254f 100644 --- a/spring-core/src/main/java/org/springframework/core/env/PropertySources.java +++ b/spring-core/src/main/java/org/springframework/core/env/PropertySources.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2018 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. @@ -16,16 +16,29 @@ package org.springframework.core.env; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + import org.springframework.lang.Nullable; /** * Holder containing one or more {@link PropertySource} objects. * * @author Chris Beams + * @author Juergen Hoeller * @since 3.1 + * @see PropertySource */ public interface PropertySources extends Iterable> { + /** + * Return a sequential {@link Stream} containing the property sources. + * @since 5.1 + */ + default Stream> stream() { + return StreamSupport.stream(spliterator(), false); + } + /** * Return whether a property source with the given name is contained. * @param name the {@linkplain PropertySource#getName() name of the property source} to find diff --git a/spring-core/src/test/java/org/springframework/core/env/MutablePropertySourcesTests.java b/spring-core/src/test/java/org/springframework/core/env/MutablePropertySourcesTests.java index 7ec6d966d9..9ef30f5eda 100644 --- a/spring-core/src/test/java/org/springframework/core/env/MutablePropertySourcesTests.java +++ b/spring-core/src/test/java/org/springframework/core/env/MutablePropertySourcesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2018 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. @@ -16,6 +16,8 @@ package org.springframework.core.env; +import java.util.Iterator; + import org.junit.Test; import org.springframework.mock.env.MockPropertySource; @@ -46,9 +48,9 @@ public class MutablePropertySourcesTests { assertThat(sources.contains("g"), is(false)); assertThat(sources.get("b"), not(nullValue())); - assertThat(sources.get("b").getProperty("p1"), equalTo((Object)"bValue")); + assertThat(sources.get("b").getProperty("p1"), equalTo("bValue")); assertThat(sources.get("d"), not(nullValue())); - assertThat(sources.get("d").getProperty("p1"), equalTo((Object)"dValue")); + assertThat(sources.get("d").getProperty("p1"), equalTo("dValue")); sources.addBefore("b", new MockPropertySource("a")); sources.addAfter("b", new MockPropertySource("c")); @@ -153,4 +155,48 @@ public class MutablePropertySourcesTests { assertThat(sources.get("bogus"), nullValue()); } + @Test + public void iteratorContainsPropertySource() { + MutablePropertySources sources = new MutablePropertySources(); + sources.addLast(new MockPropertySource("test")); + + Iterator> it = sources.iterator(); + assertTrue(it.hasNext()); + assertEquals("test", it.next().getName()); + + try { + it.remove(); + fail("Should have thrown UnsupportedOperationException"); + } + catch (UnsupportedOperationException ex) { + // expected + } + assertFalse(it.hasNext()); + } + + @Test + public void iteratorIsEmptyForEmptySources() { + MutablePropertySources sources = new MutablePropertySources(); + Iterator> it = sources.iterator(); + assertFalse(it.hasNext()); + } + + @Test + public void streamContainsPropertySource() { + MutablePropertySources sources = new MutablePropertySources(); + sources.addLast(new MockPropertySource("test")); + + assertThat(sources.stream(), notNullValue()); + assertThat(sources.stream().count(), is(1L)); + assertThat(sources.stream().anyMatch(source -> "test".equals(source.getName())), is(true)); + assertThat(sources.stream().anyMatch(source -> "bogus".equals(source.getName())), is(false)); + } + + @Test + public void streamIsEmptyForEmptySources() { + MutablePropertySources sources = new MutablePropertySources(); + assertThat(sources.stream(), notNullValue()); + assertThat(sources.stream().count(), is(0L)); + } + }