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:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user