/*
* 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.jdbi.v3.core.collector;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collector;
import java.util.stream.Stream;
import org.jdbi.v3.core.generic.GenericType;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.entry;
import static org.jdbi.v3.core.generic.GenericTypes.getErasedType;
import static org.jdbi.v3.core.generic.GenericTypes.resolveMapEntryType;
public class BuiltInCollectorFactoryTest {
private BuiltInCollectorFactory factory = new BuiltInCollectorFactory();
@Test
public void optional() {
Type optionalString = new GenericType<Optional<String>>() {}.getType();
assertThat(factory.accepts(optionalString)).isTrue();
assertThat(factory.accepts(Optional.class)).isFalse();
assertThat(factory.elementType(optionalString)).contains(String.class);
Collector<String, ?, Optional<String>> collector = (Collector<String, ?, Optional<String>>) factory.build(optionalString);
assertThat(Stream.<String>empty().collect(collector)).isEmpty();
assertThat(Stream.of("foo").collect(collector)).contains("foo");
assertThatThrownBy(() -> Stream.of("foo", "bar").collect(collector))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Multiple values");
}
@Test
public void collections() {
testCollectionType(new GenericType<Collection<String>>(){});
testCollectionType(new GenericType<List<String>>(){});
testCollectionType(new GenericType<ArrayList<String>>(){});
testCollectionType(new GenericType<LinkedList<String>>(){});
testCollectionType(new GenericType<Set<String>>(){});
testCollectionType(new GenericType<HashSet<String>>(){});
testCollectionType(new GenericType<SortedSet<String>>(){});
testCollectionType(new GenericType<TreeSet<String>>(){});
}
private <C extends Collection<String>> void testCollectionType(GenericType<C> genericType) {
Type containerType = genericType.getType();
Class<?> erasedType = getErasedType(containerType);
assertThat(factory.accepts(containerType)).isTrue();
assertThat(factory.accepts(erasedType)).isFalse();
assertThat(factory.elementType(containerType)).contains(String.class);
Collector<String, ?, C> collector = (Collector<String, ?, C>) factory.build(containerType);
assertThat(Stream.of("foo", "bar", "baz").collect(collector))
.isInstanceOf(erasedType)
.containsOnly("foo", "bar", "baz");
}
@Test
public void maps() {
testMapType(new GenericType<Map<Long, String>>() {});
testMapType(new GenericType<HashMap<Long, String>>() {});
testMapType(new GenericType<LinkedHashMap<Long, String>>() {});
testMapType(new GenericType<SortedMap<Long, String>>() {});
testMapType(new GenericType<TreeMap<Long, String>>() {});
testMapType(new GenericType<ConcurrentMap<Long, String>>() {});
testMapType(new GenericType<ConcurrentHashMap<Long, String>>() {});
testMapType(new GenericType<WeakHashMap<Long, String>>() {});
}
private <M extends Map<Long,String>> void testMapType(GenericType<M> genericType) {
Type containerType = genericType.getType();
Class<?> erasedType = getErasedType(containerType);
assertThat(factory.accepts(containerType)).isTrue();
assertThat(factory.accepts(erasedType)).isFalse();
assertThat(factory.elementType(containerType)).contains(resolveMapEntryType(Long.class, String.class));
Collector<Map.Entry<Long, String>, ?, M> collector = (Collector<Map.Entry<Long, String>, ?, M>) factory.build(containerType);
assertThat(Stream.of(entry(1L, "foo"), entry(2L, "bar"), entry(3L, "baz")).collect(collector))
.isInstanceOf(erasedType)
.containsOnly(entry(1L, "foo"), entry(2L, "bar"), entry(3L, "baz"));
assertThatThrownBy(() -> Stream.of(entry(1L, "foo"), entry(1L, "bar")).collect(collector))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Multiple values");
}
}