blob: ac6b34e5b1c9463a1f565be42fc1b76d7f37dd91 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.osgi.util.converter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.osgi.util.function.Function;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class ConverterBuilderTest {
private Converter converter;
@Before
public void setUp() {
converter = Converters.standardConverter();
}
@After
public void tearDown() {
converter = null;
}
@Test
public void testStringArrayToStringAdapter() {
ConverterBuilder cb = converter.newConverterBuilder();
Converter ca = cb.
rule(new TypeRule<String[],String>(String[].class, String.class,
v -> Stream.of(v).collect(Collectors.joining(",")))).
rule(new TypeRule<String,String[]>(String.class, String[].class,
v -> v.split(","))).
build();
assertEquals("A", converter.convert(new String[] {"A", "B"}).to(String.class));
assertEquals("A,B", ca.convert(new String[] {"A", "B"}).to(String.class));
assertArrayEquals(new String [] {"A,B"},
converter.convert("A,B").to(String[].class));
assertArrayEquals(new String [] {"A","B"},
ca.convert("A,B").to(String[].class));
}
static String convertToString(char[] a) {
StringBuilder sb = new StringBuilder();
for (char c : a) {
sb.append(c);
}
return sb.toString();
}
@Test
public void testSecondLevelAdapter() {
ConverterBuilder cb = converter.newConverterBuilder();
cb.rule(new TypeRule<>(char[].class, String.class, ConverterBuilderTest::convertToString));
cb.rule(Integer.class, (f,t) -> -1);
cb.rule(Long.class, (f,t) -> -1L);
Converter ca = cb.build();
assertEquals("hi", ca.convert(new char[] {'h', 'i'}).to(String.class));
assertEquals(Integer.valueOf(-1), ca.convert("Hello").to(Integer.class));
assertEquals(Long.valueOf(-1), ca.convert("Hello").to(Long.class));
// Shadow the Integer variant but keep Long going to the Number variant.
Converter ca2 = ca.newConverterBuilder().rule(
new TypeRule<String,Integer>(String.class, Integer.class, s -> s.length())).build();
assertEquals(5, (int) ca2.convert("Hello").to(Integer.class));
assertEquals(Long.valueOf(-1), ca2.convert("Hello").to(Long.class));
}
@Test @Ignore
public void testConvertToBaseArray() {
// TODO
}
@Test @Ignore
public void testThrowExceptionInCustomConverter() {
// TODO
}
@Test @Ignore
public void testMixedListToNumberCase() {
// TODO
}
@Test
public void testCannotHandleSpecific() {
Converter ca = converter.newConverterBuilder().rule(
new TypeRule<>(Integer.class, Long.class, new Function<Integer,Long>() {
@Override
public Long apply(Integer obj) {
if (obj.intValue() != 1)
return new Long(-obj.intValue());
return null;
}
})).build();
assertEquals(Long.valueOf(-2), ca.convert(Integer.valueOf(2)).to(Long.class));
// This is the exception that the rule cannot handle
assertEquals(Long.valueOf(1), ca.convert(Integer.valueOf(1)).to(Long.class));
}
@Test
public void testWildcardAdapter() {
ConverterFunction foo = new ConverterFunction() {
@Override
public Object apply(Object obj, Type type) throws Exception {
if (!(obj instanceof List))
return ConverterFunction.CANNOT_HANDLE;
List<?> t = (List<?>) obj;
if (t.size() == 0)
// Empty list is converted to null
return null;
if (type instanceof Class) {
if (Number.class.isAssignableFrom((Class<?>) type))
return converter.convert(t.size()).to(type);
}
return ConverterFunction.CANNOT_HANDLE;
}
};
ConverterBuilder cb = converter.newConverterBuilder();
cb.rule(foo);
cb.rule((v,t) -> v.toString());
Converter ca = cb.build();
assertEquals(3L, (long) ca.convert(Arrays.asList("a", "b", "c")).to(Long.class));
assertEquals(3, (long) ca.convert(Arrays.asList("a", "b", "c")).to(Integer.class));
assertEquals("[a, b, c]", ca.convert(Arrays.asList("a", "b", "c")).to(String.class));
assertNull(ca.convert(Arrays.asList()).to(String.class));
}
@Test
public void testWildcardAdapter1() {
ConverterFunction foo = new ConverterFunction() {
@Override
public Object apply(Object obj, Type type) throws Exception {
if (!(obj instanceof List))
return ConverterFunction.CANNOT_HANDLE;
List<?> t = (List<?>) obj;
if (type instanceof Class) {
if (Number.class.isAssignableFrom((Class<?>) type))
return converter.convert(t.size()).to(type);
}
return ConverterFunction.CANNOT_HANDLE;
}
};
ConverterBuilder cb = converter.newConverterBuilder();
cb.rule((v,t) -> converter.convert(1).to(t));
cb.rule(foo);
Converter ca = cb.build();
// The catchall converter should be called always because it can handle all and was registered first
assertEquals(1L, (long) ca.convert(Arrays.asList("a", "b", "c")).to(Long.class));
assertEquals(1, (int) ca.convert(Arrays.asList("a", "b", "c")).to(Integer.class));
assertEquals("1", ca.convert(Arrays.asList("a", "b", "c")).to(String.class));
}
@Test
public void testWildcardAdapter2() {
Map<Object, Object> snooped = new HashMap<>();
ConverterBuilder cb = converter.newConverterBuilder();
cb.rule(new Rule<String[],ArrayList<String>>(v -> {
Arrays.sort(v, Collections.reverseOrder());
return new ArrayList<>(Arrays.asList(v));
}) {});
cb.rule(new Rule<String[],List<String>>(v -> {
Arrays.sort(v, Collections.reverseOrder());
return new CopyOnWriteArrayList<>(Arrays.asList(v));
}) {});
cb.rule((v,t) -> { snooped.put(v,t); return ConverterFunction.CANNOT_HANDLE;});
Converter ca = cb.build();
assertEquals(new ArrayList<>(Arrays.asList("c", "b", "a")), ca.convert(
new String [] {"a", "b", "c"}).to(new TypeReference<ArrayList<String>>() {}));
assertEquals("Precondition", 0, snooped.size());
String[] sa0 = new String [] {"a", "b", "c"};
assertEquals(new LinkedList<>(Arrays.asList("a", "b", "c")), ca.convert(
sa0).to(LinkedList.class));
assertEquals(1, snooped.size());
assertEquals(LinkedList.class, snooped.get(sa0));
assertEquals(new CopyOnWriteArrayList<>(Arrays.asList("c", "b", "a")), ca.convert(
new String [] {"a", "b", "c"}).to(new TypeReference<List<String>>() {}));
snooped.clear();
String[] sa = new String [] {"a", "b", "c"};
assertEquals(new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c")), ca.convert(
sa).to(CopyOnWriteArrayList.class));
assertEquals(1, snooped.size());
assertEquals(CopyOnWriteArrayList.class, snooped.get(sa));
}
static interface MyIntf {
int value();
}
static class MyBean implements MyIntf {
int intfVal;
String beanVal;
@Override
public int value() {
return intfVal;
}
public String getValue() {
return beanVal;
}
}
static class MyCustomDTO {
public String field;
}
}