Add converter support for Stream
Add StreamConverter to provide full support for converting java.util.stream.Stream instances to and from collections or arrays. Also attempt to convert the element type if necessary. StreamConverter is registered by default in the DefaultConversionService as long as Java8 is available. Issue: SPR-12175
This commit is contained in:
parent
c3408d869c
commit
018adb04f2
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
@ -23,9 +23,11 @@ import java.lang.reflect.Type;
|
|||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.UsesJava8;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
@ -38,6 +40,7 @@ import org.springframework.util.ObjectUtils;
|
|||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
|
@ -45,6 +48,9 @@ public class TypeDescriptor implements Serializable {
|
|||
|
||||
static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
||||
|
||||
private static final boolean streamAvailable = ClassUtils.isPresent(
|
||||
"java.util.stream.Stream", TypeDescriptor.class.getClassLoader());
|
||||
|
||||
private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<Class<?>, TypeDescriptor>(18);
|
||||
|
||||
private static final Class<?>[] CACHED_COMMON_TYPES = {
|
||||
|
@ -316,6 +322,7 @@ public class TypeDescriptor implements Serializable {
|
|||
|
||||
/**
|
||||
* If this type is an array, returns the array's component type.
|
||||
* If this type is a {@code Stream}, returns the stream's component type.
|
||||
* If this type is a {@link Collection} and it is parameterized, returns the Collection's element type.
|
||||
* If the Collection is not parameterized, returns {@code null} indicating the element type is not declared.
|
||||
* @return the array component type or Collection element type, or {@code null} if this type is a
|
||||
|
@ -326,6 +333,9 @@ public class TypeDescriptor implements Serializable {
|
|||
if (this.resolvableType.isArray()) {
|
||||
return new TypeDescriptor(this.resolvableType.getComponentType(), null, this.annotations);
|
||||
}
|
||||
if (streamAvailable && StreamHelper.isStream(this.type)) {
|
||||
return StreamHelper.getStreamElementType(this);
|
||||
}
|
||||
return getRelatedIfResolvable(this, this.resolvableType.asCollection().getGeneric());
|
||||
}
|
||||
|
||||
|
@ -681,4 +691,19 @@ public class TypeDescriptor implements Serializable {
|
|||
return new TypeDescriptor(type, null, source.annotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class to avoid a hard dependency on Java 8.
|
||||
*/
|
||||
@UsesJava8
|
||||
private static class StreamHelper {
|
||||
|
||||
private static boolean isStream(Class<?> type) {
|
||||
return Stream.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
private static TypeDescriptor getStreamElementType(TypeDescriptor source) {
|
||||
return getRelatedIfResolvable(source, source.resolvableType.as(Stream.class).getGeneric());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
|
@ -33,6 +33,7 @@ import org.springframework.util.ClassUtils;
|
|||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 3.1
|
||||
*/
|
||||
public class DefaultConversionService extends GenericConversionService {
|
||||
|
@ -45,6 +46,11 @@ public class DefaultConversionService extends GenericConversionService {
|
|||
private static final boolean jsr310Available =
|
||||
ClassUtils.isPresent("java.time.ZoneId", DefaultConversionService.class.getClassLoader());
|
||||
|
||||
/** Java 8's java.util.stream.Stream class available? */
|
||||
private static final boolean streamAvailable = ClassUtils.isPresent(
|
||||
"java.util.stream.Stream", DefaultConversionService.class.getClassLoader());
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code DefaultConversionService} with the set of
|
||||
|
@ -132,6 +138,10 @@ public class DefaultConversionService extends GenericConversionService {
|
|||
|
||||
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
|
||||
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
|
||||
|
||||
if (streamAvailable) {
|
||||
converterRegistry.addConverter(new StreamConverter(conversionService));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2002-2015 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.core.convert.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.lang.UsesJava8;
|
||||
|
||||
/**
|
||||
* Convert a {@link Stream} to an from a collection or array, converting the
|
||||
* element type if necessary.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.2
|
||||
*/
|
||||
@UsesJava8
|
||||
public class StreamConverter implements ConditionalGenericConverter {
|
||||
|
||||
private static final TypeDescriptor STREAM_TYPE = TypeDescriptor.valueOf(Stream.class);
|
||||
|
||||
private static final Set<ConvertiblePair> CONVERTIBLE_TYPES = createConvertibleTypes();
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
public StreamConverter(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return CONVERTIBLE_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (sourceType.isAssignableTo(STREAM_TYPE)) {
|
||||
return matchesFromStream(sourceType.getElementTypeDescriptor(), targetType);
|
||||
}
|
||||
if (targetType.isAssignableTo(STREAM_TYPE)) {
|
||||
return matchesToStream(targetType.getElementTypeDescriptor(), sourceType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that a {@link Collection} of the elements held within the stream can be
|
||||
* converted to the specified {@code targetType}.
|
||||
* @param elementType the type of the stream elements
|
||||
* @param targetType the type to convert to
|
||||
*/
|
||||
public boolean matchesFromStream(TypeDescriptor elementType, TypeDescriptor targetType) {
|
||||
TypeDescriptor collectionOfElement = TypeDescriptor.collection(Collection.class, elementType);
|
||||
return this.conversionService.canConvert(collectionOfElement, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the specified {@code sourceType} can be converted to a {@link Collection} of
|
||||
* type type of the stream elements
|
||||
* @param elementType the type of the stream elements
|
||||
* @param sourceType the type to convert from
|
||||
*/
|
||||
public boolean matchesToStream(TypeDescriptor elementType, TypeDescriptor sourceType) {
|
||||
TypeDescriptor collectionOfElement = TypeDescriptor.collection(Collection.class, elementType);
|
||||
return this.conversionService.canConvert(sourceType, collectionOfElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (sourceType.isAssignableTo(STREAM_TYPE)) {
|
||||
return convertFromStream((Stream<?>) source, sourceType, targetType);
|
||||
}
|
||||
if (targetType.isAssignableTo(STREAM_TYPE)) {
|
||||
return convertToStream(source, sourceType, targetType);
|
||||
}
|
||||
// Should not happen
|
||||
throw new IllegalStateException("Unexpected source/target types");
|
||||
}
|
||||
|
||||
private Object convertFromStream(Stream<?> source, TypeDescriptor streamType, TypeDescriptor targetType) {
|
||||
List<Object> content = source.collect(Collectors.toList());
|
||||
TypeDescriptor listType = TypeDescriptor.collection(List.class, streamType.getElementTypeDescriptor());
|
||||
return this.conversionService.convert(content, listType, targetType);
|
||||
}
|
||||
|
||||
private Object convertToStream(Object source, TypeDescriptor sourceType, TypeDescriptor streamType) {
|
||||
TypeDescriptor targetCollection =
|
||||
TypeDescriptor.collection(List.class, streamType.getElementTypeDescriptor());
|
||||
List<?> target = (List<?>) this.conversionService.convert(source, sourceType, targetCollection);
|
||||
return target.stream();
|
||||
}
|
||||
|
||||
|
||||
private static Set<ConvertiblePair> createConvertibleTypes() {
|
||||
Set<ConvertiblePair> convertiblePairs = new HashSet<ConvertiblePair>();
|
||||
convertiblePairs.add(new ConvertiblePair(Stream.class, Collection.class));
|
||||
convertiblePairs.add(new ConvertiblePair(Stream.class, Object[].class));
|
||||
convertiblePairs.add(new ConvertiblePair(Collection.class, Stream.class));
|
||||
convertiblePairs.add(new ConvertiblePair(Object[].class, Stream.class));
|
||||
return convertiblePairs;
|
||||
}
|
||||
|
||||
}
|
|
@ -36,6 +36,7 @@ import java.util.Map;
|
|||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -53,6 +54,7 @@ import static org.junit.Assert.*;
|
|||
/**
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class DefaultConversionTests {
|
||||
|
||||
|
@ -81,24 +83,24 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void testStringToBooleanTrue() {
|
||||
assertEquals(Boolean.valueOf(true), conversionService.convert("true", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(true), conversionService.convert("on", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(true), conversionService.convert("yes", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(true), conversionService.convert("1", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(true), conversionService.convert("TRUE", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(true), conversionService.convert("ON", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(true), conversionService.convert("YES", Boolean.class));
|
||||
assertEquals(true, conversionService.convert("true", Boolean.class));
|
||||
assertEquals(true, conversionService.convert("on", Boolean.class));
|
||||
assertEquals(true, conversionService.convert("yes", Boolean.class));
|
||||
assertEquals(true, conversionService.convert("1", Boolean.class));
|
||||
assertEquals(true, conversionService.convert("TRUE", Boolean.class));
|
||||
assertEquals(true, conversionService.convert("ON", Boolean.class));
|
||||
assertEquals(true, conversionService.convert("YES", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringToBooleanFalse() {
|
||||
assertEquals(Boolean.valueOf(false), conversionService.convert("false", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(false), conversionService.convert("off", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(false), conversionService.convert("no", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(false), conversionService.convert("0", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(false), conversionService.convert("FALSE", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(false), conversionService.convert("OFF", Boolean.class));
|
||||
assertEquals(Boolean.valueOf(false), conversionService.convert("NO", Boolean.class));
|
||||
assertEquals(false, conversionService.convert("false", Boolean.class));
|
||||
assertEquals(false, conversionService.convert("off", Boolean.class));
|
||||
assertEquals(false, conversionService.convert("no", Boolean.class));
|
||||
assertEquals(false, conversionService.convert("0", Boolean.class));
|
||||
assertEquals(false, conversionService.convert("FALSE", Boolean.class));
|
||||
assertEquals(false, conversionService.convert("OFF", Boolean.class));
|
||||
assertEquals(false, conversionService.convert("NO", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -123,7 +125,7 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void testByteToString() {
|
||||
assertEquals("65", conversionService.convert(new String("A").getBytes()[0], String.class));
|
||||
assertEquals("65", conversionService.convert("A".getBytes()[0], String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -227,11 +229,11 @@ public class DefaultConversionTests {
|
|||
assertEquals("BAR", conversionService.convert(Foo.BAR, String.class));
|
||||
}
|
||||
|
||||
public static enum Foo {
|
||||
public enum Foo {
|
||||
BAR, BAZ
|
||||
}
|
||||
|
||||
public static enum SubFoo {
|
||||
public enum SubFoo {
|
||||
|
||||
BAR {
|
||||
@Override
|
||||
|
@ -262,12 +264,12 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void testNumberToNumber() {
|
||||
assertEquals(Long.valueOf(1), conversionService.convert(Integer.valueOf(1), Long.class));
|
||||
assertEquals(Long.valueOf(1), conversionService.convert(1, Long.class));
|
||||
}
|
||||
|
||||
@Test(expected=ConversionFailedException.class)
|
||||
public void testNumberToNumberNotSupportedNumber() {
|
||||
conversionService.convert(Integer.valueOf(1), CustomNumber.class);
|
||||
conversionService.convert(1, CustomNumber.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
|
@ -297,7 +299,7 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void testNumberToCharacter() {
|
||||
assertEquals(Character.valueOf('A'), conversionService.convert(Integer.valueOf(65), Character.class));
|
||||
assertEquals(Character.valueOf('A'), conversionService.convert(65, Character.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -319,6 +321,7 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void convertArrayToCollectionGenericTypeConversion() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> result = (List<Integer>) conversionService.convert(new String[] { "1", "2", "3" }, TypeDescriptor
|
||||
.valueOf(String[].class), new TypeDescriptor(getClass().getDeclaredField("genericList")));
|
||||
assertEquals(new Integer("1"), result.get(0));
|
||||
|
@ -326,11 +329,26 @@ public class DefaultConversionTests {
|
|||
assertEquals(new Integer("3"), result.get(2));
|
||||
}
|
||||
|
||||
public Stream<Integer> genericStream;
|
||||
|
||||
@Test
|
||||
public void convertArrayToStream() throws Exception {
|
||||
String[] source = {"1", "3", "4"};
|
||||
@SuppressWarnings("unchecked")
|
||||
Stream<Integer> result = (Stream<Integer>) this.conversionService.convert(source,
|
||||
TypeDescriptor.valueOf(String[].class),
|
||||
new TypeDescriptor(getClass().getDeclaredField("genericStream")));
|
||||
assertEquals(8, result.mapToInt((x) -> x).sum());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpr7766() throws Exception {
|
||||
ConverterRegistry registry = (conversionService);
|
||||
registry.addConverter(new ColorConverter());
|
||||
List<Color> colors = (List<Color>) conversionService.convert(new String[] { "ffffff", "#000000" }, TypeDescriptor.valueOf(String[].class), new TypeDescriptor(new MethodParameter(getClass().getMethod("handlerMethod", List.class), 0)));
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Color> colors = (List<Color>) conversionService.convert(new String[] { "ffffff", "#000000" },
|
||||
TypeDescriptor.valueOf(String[].class),
|
||||
new TypeDescriptor(new MethodParameter(getClass().getMethod("handlerMethod", List.class), 0)));
|
||||
assertEquals(2, colors.size());
|
||||
assertEquals(Color.WHITE, colors.get(0));
|
||||
assertEquals(Color.BLACK, colors.get(1));
|
||||
|
@ -474,14 +492,14 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void convertCollectionToString() {
|
||||
List<String> list = Arrays.asList(new String[] { "foo", "bar" });
|
||||
List<String> list = Arrays.asList("foo", "bar");
|
||||
String result = conversionService.convert(list, String.class);
|
||||
assertEquals("foo,bar", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertCollectionToStringWithElementConversion() throws Exception {
|
||||
List<Integer> list = Arrays.asList(new Integer[] { 3, 5 });
|
||||
List<Integer> list = Arrays.asList(3, 5);
|
||||
String result = (String) conversionService.convert(list,
|
||||
new TypeDescriptor(getClass().getField("genericList")), TypeDescriptor.valueOf(String.class));
|
||||
assertEquals("3,5", result);
|
||||
|
@ -501,9 +519,9 @@ public class DefaultConversionTests {
|
|||
List result = (List) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class),
|
||||
new TypeDescriptor(getClass().getField("genericList")));
|
||||
assertEquals(3, result.size());
|
||||
assertEquals(new Integer(1), result.get(0));
|
||||
assertEquals(new Integer(2), result.get(1));
|
||||
assertEquals(new Integer(3), result.get(2));
|
||||
assertEquals(1, result.get(0));
|
||||
assertEquals(2, result.get(1));
|
||||
assertEquals(3, result.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -551,6 +569,7 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void convertObjectToCollection() {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> result = (List<String>) conversionService.convert(3L, List.class);
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(3L, result.get(0));
|
||||
|
@ -558,6 +577,7 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void convertObjectToCollectionWithElementConversion() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> result = (List<Integer>) conversionService.convert(3L, TypeDescriptor.valueOf(Long.class),
|
||||
new TypeDescriptor(getClass().getField("genericList")));
|
||||
assertEquals(1, result.size());
|
||||
|
@ -594,6 +614,7 @@ public class DefaultConversionTests {
|
|||
foo.add("1");
|
||||
foo.add("2");
|
||||
foo.add("3");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> bar = (List<Integer>) conversionService.convert(foo, TypeDescriptor.forObject(foo),
|
||||
new TypeDescriptor(getClass().getField("genericList")));
|
||||
assertEquals(new Integer(1), bar.get(0));
|
||||
|
@ -603,6 +624,7 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void convertCollectionToCollectionNull() throws Exception {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> bar = (List<Integer>) conversionService.convert(null,
|
||||
TypeDescriptor.valueOf(LinkedHashSet.class), new TypeDescriptor(getClass().getField("genericList")));
|
||||
assertNull(bar);
|
||||
|
@ -621,6 +643,7 @@ public class DefaultConversionTests {
|
|||
assertEquals("3", bar.get(2));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void convertCollectionToCollectionSpecialCaseSourceImpl() throws Exception {
|
||||
Map map = new LinkedHashMap();
|
||||
|
@ -641,7 +664,9 @@ public class DefaultConversionTests {
|
|||
List<String> strings = new ArrayList<String>();
|
||||
strings.add("3");
|
||||
strings.add("9");
|
||||
List<Integer> integers = (List<Integer>) conversionService.convert(strings, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)));
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> integers = (List<Integer>) conversionService.convert(strings,
|
||||
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)));
|
||||
assertEquals(new Integer(3), integers.get(0));
|
||||
assertEquals(new Integer(9), integers.get(1));
|
||||
}
|
||||
|
@ -653,7 +678,8 @@ public class DefaultConversionTests {
|
|||
Map<String, String> foo = new HashMap<String, String>();
|
||||
foo.put("1", "BAR");
|
||||
foo.put("2", "BAZ");
|
||||
Map<String, FooEnum> map = (Map<String, FooEnum>) conversionService.convert(foo,
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Integer, FooEnum> map = (Map<Integer, FooEnum>) conversionService.convert(foo,
|
||||
TypeDescriptor.forObject(foo), new TypeDescriptor(getClass().getField("genericMap")));
|
||||
assertEquals(FooEnum.BAR, map.get(1));
|
||||
assertEquals(FooEnum.BAZ, map.get(2));
|
||||
|
@ -664,7 +690,9 @@ public class DefaultConversionTests {
|
|||
Map<String, String> strings = new HashMap<String, String>();
|
||||
strings.put("3", "9");
|
||||
strings.put("6", "31");
|
||||
Map<Integer, Integer> integers = (Map<Integer, Integer>) conversionService.convert(strings, TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Integer.class)));
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Integer, Integer> integers = (Map<Integer, Integer>) conversionService.convert(strings,
|
||||
TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Integer.class)));
|
||||
assertEquals(new Integer(9), integers.get(3));
|
||||
assertEquals(new Integer(31), integers.get(6));
|
||||
}
|
||||
|
@ -747,7 +775,8 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void convertObjectToObjectFinderMethodWithNull() {
|
||||
TestEntity e = (TestEntity) conversionService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(TestEntity.class));
|
||||
TestEntity e = (TestEntity) conversionService.convert(null,
|
||||
TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(TestEntity.class));
|
||||
assertNull(e);
|
||||
}
|
||||
|
||||
|
@ -803,7 +832,8 @@ public class DefaultConversionTests {
|
|||
|
||||
@Test
|
||||
public void convertObjectToOptionalNull() {
|
||||
assertSame(Optional.empty(), conversionService.convert(null, TypeDescriptor.valueOf(Object.class), TypeDescriptor.valueOf(Optional.class)));
|
||||
assertSame(Optional.empty(), conversionService.convert(null, TypeDescriptor.valueOf(Object.class),
|
||||
TypeDescriptor.valueOf(Optional.class)));
|
||||
assertSame(Optional.empty(), conversionService.convert(null, Optional.class));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright 2002-2015 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.core.convert.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class StreamConverterTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private GenericConversionService conversionService;
|
||||
|
||||
private StreamConverter streamConverter;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.conversionService = new GenericConversionService();
|
||||
this.streamConverter = new StreamConverter(this.conversionService);
|
||||
|
||||
this.conversionService.addConverter(new CollectionToCollectionConverter(this.conversionService));
|
||||
this.conversionService.addConverter(new ArrayToCollectionConverter(this.conversionService));
|
||||
this.conversionService.addConverter(new CollectionToArrayConverter(this.conversionService));
|
||||
this.conversionService.addConverter(this.streamConverter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromStreamToList() throws NoSuchFieldException {
|
||||
this.conversionService.addConverter(Number.class, String.class, new ObjectToStringConverter());
|
||||
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
|
||||
TypeDescriptor listOfStrings = new TypeDescriptor(Types.class.getField("listOfStrings")); ;
|
||||
Object result = this.conversionService.convert(stream, listOfStrings);
|
||||
assertNotNull("converted object must not be null", result);
|
||||
assertTrue("Converted object must be a list", result instanceof List);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> content = (List<String>) result;
|
||||
assertEquals("1", content.get(0));
|
||||
assertEquals("2", content.get(1));
|
||||
assertEquals("3", content.get(2));
|
||||
assertEquals("Wrong number of elements", 3, content.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromStreamToArray() throws NoSuchFieldException {
|
||||
this.conversionService.addConverterFactory(new NumberToNumberConverterFactory());
|
||||
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
|
||||
TypeDescriptor arrayOfLongs = new TypeDescriptor(Types.class.getField("arrayOfLongs")); ;
|
||||
Object result = this.conversionService.convert(stream, arrayOfLongs);
|
||||
assertNotNull("converted object must not be null", result);
|
||||
assertTrue("Converted object must be an array", result.getClass().isArray());
|
||||
Long[] content = (Long[]) result;
|
||||
assertEquals(Long.valueOf(1L), content[0]);
|
||||
assertEquals(Long.valueOf(2L), content[1]);
|
||||
assertEquals(Long.valueOf(3L), content[2]);
|
||||
assertEquals("Wrong number of elements", 3, content.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromStreamToRawList() throws NoSuchFieldException {
|
||||
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
|
||||
TypeDescriptor listOfStrings = new TypeDescriptor(Types.class.getField("rawList")); ;
|
||||
Object result = this.conversionService.convert(stream, listOfStrings);
|
||||
assertNotNull("converted object must not be null", result);
|
||||
assertTrue("Converted object must be a list", result instanceof List);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> content = (List<Object>) result;
|
||||
assertEquals(1, content.get(0));
|
||||
assertEquals(2, content.get(1));
|
||||
assertEquals(3, content.get(2));
|
||||
assertEquals("Wrong number of elements", 3, content.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromStreamToArrayNoConverter() throws NoSuchFieldException {
|
||||
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
|
||||
TypeDescriptor arrayOfLongs = new TypeDescriptor(Types.class.getField("arrayOfLongs")); ;
|
||||
|
||||
thrown.expect(ConversionFailedException.class);
|
||||
thrown.expectCause(is(instanceOf(ConverterNotFoundException.class)));
|
||||
this.conversionService.convert(stream, arrayOfLongs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromListToStream() throws NoSuchFieldException {
|
||||
this.conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||
List<String> stream = Arrays.asList("1", "2", "3");
|
||||
TypeDescriptor streamOfInteger = new TypeDescriptor(Types.class.getField("streamOfIntegers")); ;
|
||||
Object result = this.conversionService.convert(stream, streamOfInteger);
|
||||
assertNotNull("converted object must not be null", result);
|
||||
assertTrue("Converted object must be a stream", result instanceof Stream);
|
||||
@SuppressWarnings("unchecked")
|
||||
Stream<Integer> content = (Stream<Integer>) result;
|
||||
assertEquals(6, content.mapToInt((x) -> x).sum());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromArrayToStream() throws NoSuchFieldException {
|
||||
Integer[] stream = new Integer[] {1, 0, 1};
|
||||
this.conversionService.addConverter(new Converter<Integer, Boolean>() {
|
||||
@Override
|
||||
public Boolean convert(Integer source) {
|
||||
return source == 1;
|
||||
}
|
||||
});
|
||||
TypeDescriptor streamOfBoolean = new TypeDescriptor(Types.class.getField("streamOfBooleans")); ;
|
||||
Object result = this.conversionService.convert(stream, streamOfBoolean);
|
||||
assertNotNull("converted object must not be null", result);
|
||||
assertTrue("Converted object must be a stream", result instanceof Stream);
|
||||
@SuppressWarnings("unchecked")
|
||||
Stream<Boolean> content = (Stream<Boolean>) result;
|
||||
assertEquals(2, content.filter(x -> x).count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromListToRawStream() throws NoSuchFieldException {
|
||||
List<String> stream = Arrays.asList("1", "2", "3");
|
||||
TypeDescriptor streamOfInteger = new TypeDescriptor(Types.class.getField("rawStream")); ;
|
||||
Object result = this.conversionService.convert(stream, streamOfInteger);
|
||||
assertNotNull("converted object must not be null", result);
|
||||
assertTrue("Converted object must be a stream", result instanceof Stream);
|
||||
@SuppressWarnings("unchecked")
|
||||
Stream<Object> content = (Stream<Object>) result;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
content.forEach(sb::append);
|
||||
assertEquals("123", sb.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotMatchIfNoStream() throws NoSuchFieldException {
|
||||
assertFalse("Should not match non stream type", this.streamConverter.matches(
|
||||
new TypeDescriptor(Types.class.getField("listOfStrings")),
|
||||
new TypeDescriptor(Types.class.getField("arrayOfLongs"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFailToConvertIfNoStream() throws NoSuchFieldException {
|
||||
thrown.expect(IllegalStateException.class);
|
||||
this.streamConverter.convert(new Object(), new TypeDescriptor(Types.class.getField("listOfStrings")),
|
||||
new TypeDescriptor(Types.class.getField("arrayOfLongs")));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class Types {
|
||||
|
||||
public List<String> listOfStrings;
|
||||
|
||||
public Long[] arrayOfLongs;
|
||||
|
||||
public Stream<Integer> streamOfIntegers;
|
||||
|
||||
public Stream<Boolean> streamOfBooleans;
|
||||
|
||||
public Stream rawStream;
|
||||
|
||||
public List rawList;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue