Author: davidb Date: Mon Apr 18 10:31:25 2016 New Revision: 1739734 URL: http://svn.apache.org/viewvc?rev=1739734&view=rev Log: Felix Converter Service - Support for some special cases and interface-based conversions.
Added: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java felix/trunk/converter/src/main/java/org/osgi/service/converter/Converting.java felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java?rev=1739734&r1=1739733&r2=1739734&view=diff ============================================================================== --- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java (original) +++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/AdapterImpl.java Mon Apr 18 10:31:25 2016 @@ -17,6 +17,8 @@ package org.apache.felix.converter.impl; import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Arrays; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -30,7 +32,7 @@ import org.osgi.service.converter.TypeRe public class AdapterImpl implements Adapter { private final Converter delegate; - private final Map<ClassPair, Function<Object, Object>> classRules = + private final Map<TypePair, Function<Object, Object>> classRules = new ConcurrentHashMap<>(); public AdapterImpl(Converter converter) { @@ -55,8 +57,8 @@ public class AdapterImpl implements Adap if (fromCls.equals(toCls)) throw new IllegalArgumentException(); - classRules.put(new ClassPair(fromCls, toCls), (Function<Object, Object>) toFun); - classRules.put(new ClassPair(toCls, fromCls), (Function<Object, Object>) fromFun); + classRules.put(new TypePair(fromCls, toCls), (Function<Object, Object>) toFun); + classRules.put(new TypePair(toCls, fromCls), (Function<Object, Object>) fromFun); return this; } @@ -69,15 +71,15 @@ public class AdapterImpl implements Adap @Override public <F, T> Adapter rule(Function<F, T> toFun, Function<T, F> fromFun) { -// Type[] t = toFun.getClass().getGenericInterfaces(); -// -// TypeVariable<?>[] tp = toFun.getClass().getTypeParameters(); -// System.out.println("*** " + Arrays.toString(tp)); -// -// TypeReference<Map<String, Adapter>> tr = new TypeReference<Map<String,Adapter>>(){}; -// System.out.println("### " + tr); -// Type type = tr.getType(); -// System.out.println("### " + type); + Type[] t = toFun.getClass().getGenericInterfaces(); + + TypeVariable<?>[] tp = toFun.getClass().getTypeParameters(); + System.out.println("*** " + Arrays.toString(tp)); + + TypeReference<Map<String, Adapter>> tr = new TypeReference<Map<String,Adapter>>(){}; + System.out.println("### " + tr); + Type type = tr.getType(); + System.out.println("### " + type); // TODO Auto-generated method stub return this; @@ -92,34 +94,28 @@ public class AdapterImpl implements Adap del = c; } - @SuppressWarnings("unchecked") @Override - public <T> T to(Class<T> cls) { - Function<Object, Object> f = classRules.get(new ClassPair(object.getClass(), cls)); - if (f != null) - return (T) f.apply(object); - - return del.to(cls); - } + public Object to(Type type) { + if (object != null) { + Function<Object, Object> f = classRules.get(new TypePair(object.getClass(), type)); + if (f != null) + return f.apply(object); + } - @Override - public <T> T to(TypeReference<T> ref) { - // TODO Auto-generated method stub - return null; + return del.to(type); } @Override - public Object to(Type type) { - // TODO Auto-generated method stub - return null; + public String toString() { + return to(String.class); } } - static class ClassPair { - private final Class<?> from; - private final Class<?> to; + static class TypePair { + private final Type from; + private final Type to; - ClassPair(Class<?> from, Class<?> to) { + TypePair(Type from, Type to) { this.from = from; this.to = to; } @@ -133,10 +129,10 @@ public class AdapterImpl implements Adap public boolean equals(Object obj) { if (obj == this) return true; - if (!(obj instanceof ClassPair)) + if (!(obj instanceof TypePair)) return false; - ClassPair o = (ClassPair) obj; + TypePair o = (TypePair) obj; return Objects.equals(from, o.from) && Objects.equals(to, o.to); } Added: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java?rev=1739734&view=auto ============================================================================== --- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java (added) +++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConverterService.java Mon Apr 18 10:31:25 2016 @@ -0,0 +1,57 @@ +/* + * 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.apache.felix.converter.impl; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; +import java.util.UUID; +import java.util.regex.Pattern; + +import org.osgi.service.converter.Adapter; +import org.osgi.service.converter.Converter; +import org.osgi.service.converter.Converting; + +public class ConverterService implements Converter { + private final Adapter adapter; + + public ConverterService() { + Adapter a = new ConverterImpl().getAdapter(); + a.rule(UUID.class, String.class, UUID::toString, UUID::fromString); + a.rule(Pattern.class, String.class, Pattern::toString, Pattern::compile); + a.rule(LocalDateTime.class, String.class, LocalDateTime::toString, LocalDateTime::parse); + a.rule(LocalDate.class, String.class, LocalDate::toString, LocalDate::parse); + a.rule(LocalTime.class, String.class, LocalTime::toString, LocalTime::parse); + a.rule(OffsetDateTime.class, String.class, OffsetDateTime::toString, OffsetDateTime::parse); + a.rule(OffsetTime.class, String.class, OffsetTime::toString, OffsetTime::parse); + a.rule(ZonedDateTime.class, String.class, ZonedDateTime::toString, ZonedDateTime::parse); + adapter = a; + } + + @Override + public Converting convert(Object obj) { + return adapter.convert(obj); + } + + @Override + public Adapter getAdapter() { + return adapter.getAdapter(); + } +} Modified: felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java?rev=1739734&r1=1739733&r2=1739734&view=diff ============================================================================== --- felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java (original) +++ felix/trunk/converter/src/main/java/org/apache/felix/converter/impl/ConvertingImpl.java Mon Apr 18 10:31:25 2016 @@ -18,8 +18,10 @@ package org.apache.felix.converter.impl; import java.lang.reflect.Array; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; @@ -27,17 +29,18 @@ import java.util.Collection; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import org.osgi.service.converter.Converter; import org.osgi.service.converter.Converting; -import org.osgi.service.converter.TypeReference; public class ConvertingImpl implements Converting { private static final Map<Class<?>, Class<?>> boxedClasses; @@ -72,13 +75,6 @@ public class ConvertingImpl implements C object = obj; } - @SuppressWarnings("unchecked") - @Override - public <T> T to(Class<T> cls) { - Type type = cls; - return (T) to(type); - } - @Override public Object to(Type type) { Class<?> cls = null; @@ -123,17 +119,9 @@ public class ConvertingImpl implements C // At this point we know that the target is a 'singular' type: not a map, collection or array if (object instanceof Collection) { - Collection<?> coll = (Collection<?>) object; - if (coll.size() == 0) - return null; - else - return converter.convert(coll.iterator().next()).to(cls); + return convertCollectionToSingleValue(cls); } else if (object instanceof Object[]) { - Object[] arr = (Object[]) object; - if (arr.length == 0) - return null; - else - return converter.convert(arr[0]).to(cls); + return convertArrayToSingleValue(cls); } Object res2 = tryStandardMethods(targetCls); @@ -144,10 +132,47 @@ public class ConvertingImpl implements C } } + private Object convertArrayToSingleValue(Class<?> cls) { + Object[] arr = (Object[]) object; + if (arr.length == 0) + return null; + else + return converter.convert(arr[0]).to(cls); + } + + private Object convertCollectionToSingleValue(Class<?> cls) { + Collection<?> coll = (Collection<?>) object; + if (coll.size() == 0) + return null; + else + return converter.convert(coll.iterator().next()).to(cls); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) private Object convertToMapType(Class<?> targetCls, Type[] typeArguments) { if (Map.class.isAssignableFrom(targetCls)) return convertToMap(targetCls, typeArguments); - return null; + else if (Dictionary.class.isAssignableFrom(targetCls)) + return new Hashtable(convertToMap(Map.class, typeArguments)); + return createProxy(targetCls); + } + + @SuppressWarnings("rawtypes") + private Object createProxy(Class<?> targetCls) { + Map m = mapView(object); + return Proxy.newProxyInstance(targetCls.getClassLoader(), new Class[] {targetCls}, + new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String propName = getAccessorPropertyName(method); + if (propName == null) + return null; + + Class<?> targetType = method.getReturnType(); + + return converter.convert(m.get(propName)).to(targetType); + } + }); } @SuppressWarnings({ "rawtypes", "unchecked" }) @@ -186,7 +211,70 @@ public class ConvertingImpl implements C private static Map<?,?> mapView(Object obj) { if (obj instanceof Map) return (Map<?,?>) obj; - return null; + else if (obj instanceof Dictionary) + return null; // TODO + else + return createMapFromBeanAccessors(obj); + } + + @SuppressWarnings("rawtypes") + private static Map createMapFromBeanAccessors(Object obj) { + Set<String> invokedMethods = new HashSet<>(); + + Map result = new HashMap(); + for (Method md : obj.getClass().getDeclaredMethods()) { + handleMethod(obj, md, invokedMethods, result); + } + for (Method md : obj.getClass().getMethods()) { + handleMethod(obj, md, invokedMethods, result); + } + + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static void handleMethod(Object obj, Method md, Set<String> invokedMethods, Map res) { + String mn = md.getName(); + if (invokedMethods.contains(mn)) + return; // method with this name already invoked + + String propName = getAccessorPropertyName(md); + + try { + res.put(propName.toString(), md.invoke(obj)); + invokedMethods.add(mn); + } catch (Exception e) { + } + } + + private static String getAccessorPropertyName(Method md) { + if (md.getReturnType().equals(Void.class)) + return null; // not an accessor + + if (md.getParameterTypes().length > 0) + return null; // not an accessor + + if (Object.class.equals(md.getDeclaringClass())) + return null; // do not use any methods on the Object class as a accessor + + String mn = md.getName(); + int prefix; + if (mn.startsWith("get")) + prefix = 3; + else if (mn.startsWith("is")) + prefix = 2; + else + return null; // not an accessor prefix + + if (mn.length() <= prefix) + return null; // just 'get' or 'is': not an accessor + String propStr = mn.substring(prefix); + StringBuilder propName = new StringBuilder(propStr.length()); + propName.append(Character.toLowerCase(propStr.charAt(0))); + if (propStr.length() > 1) + propName.append(propStr.substring(1)); + + return propName.toString(); } private boolean isMapType(Class<?> targetCls) { @@ -285,13 +373,9 @@ public class ConvertingImpl implements C return cls; } - @SuppressWarnings("unchecked") - @Override - public <T> T to(TypeReference<T> ref) { - return (T) to(ref.getType()); - } - private Object trySpecialCases(Class<?> targetCls) { + // TODO some of these can probably be implemented as an adapter + if (Boolean.class.equals(targetCls)) { if (object instanceof Character) { return ((Character) object).charValue() != (char) 0; Modified: felix/trunk/converter/src/main/java/org/osgi/service/converter/Converting.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/main/java/org/osgi/service/converter/Converting.java?rev=1739734&r1=1739733&r2=1739734&view=diff ============================================================================== --- felix/trunk/converter/src/main/java/org/osgi/service/converter/Converting.java (original) +++ felix/trunk/converter/src/main/java/org/osgi/service/converter/Converting.java Mon Apr 18 10:31:25 2016 @@ -31,7 +31,11 @@ public interface Converting { * @param cls The class to convert to. * @return The converted object. */ - <T> T to(Class<T> cls); + @SuppressWarnings("unchecked") + default <T> T to(Class<T> cls) { + Type type = cls; + return (T) to(type); + } /** * Specify the target object type as a {@link TypeReference}. If the target @@ -48,7 +52,10 @@ public interface Converting { * @param ref A type reference to the object being converted to. * @return The converted object. */ - <T> T to(TypeReference<T> ref); + @SuppressWarnings("unchecked") + default <T> T to(TypeReference<T> ref) { + return (T) to(ref.getType()); + } /** * Specify the target object type as a Java Refelection Type object. Modified: felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java?rev=1739734&r1=1739733&r2=1739734&view=diff ============================================================================== --- felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java (original) +++ felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterMapTest.java Mon Apr 18 10:31:25 2016 @@ -16,7 +16,11 @@ */ package org.apache.felix.converter.impl; +import java.math.BigInteger; +import java.net.URL; import java.util.Collections; +import java.util.Dictionary; +import java.util.HashMap; import java.util.Map; import org.junit.After; @@ -26,6 +30,10 @@ import org.osgi.service.converter.Conver import org.osgi.service.converter.TypeReference; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; public class ConverterMapTest { private Converter converter; @@ -47,4 +55,107 @@ public class ConverterMapTest { assertEquals(1, m2.size()); assertEquals(987654321L, (long) m2.get("42")); } + + @Test + public void testConvertMapToDictionary() throws Exception { + Map<BigInteger, URL> m = new HashMap<>(); + BigInteger bi = new BigInteger("123"); + URL url = new URL("http://0.0.0.0:123"); + m.put(bi, url); + + @SuppressWarnings("unchecked") + Dictionary<BigInteger, URL> d = converter.convert(m).to(Dictionary.class); + assertEquals(1, d.size()); + assertSame(bi, d.keys().nextElement()); + assertSame(url, d.get(bi)); + } + + @Test + public void testInterfaceToMap() { + Object obj = new Object(); + TestInterface impl = new TestInterface() { + @Override + public String getFoo() { + return "Chocolate!"; + } + + @Override + public int getbar() { + return 76543; + } + + @SuppressWarnings("unused") + public long getL() { + return 1L; + } + + @SuppressWarnings("unused") + public boolean isSomething() { + return true; + } + + @SuppressWarnings("unused") + public Object getBlah() { + return obj; + } + + @SuppressWarnings("unused") + private byte getByte() { + return (byte) 12; + } + + @SuppressWarnings("unused") + public String getAlt(int arg) { + return "some value"; + } + }; + + @SuppressWarnings("rawtypes") + Map m = converter.convert(impl).to(Map.class); + assertEquals(5, m.size()); + assertEquals("Chocolate!", m.get("foo")); + assertEquals(76543, (int) m.get("bar")); + assertEquals(1L, (long) m.get("l")); + assertTrue((boolean) m.get("something")); + assertSame(obj, m.get("blah")); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testMapToInterface1() { + Map m = new HashMap<>(); + m.put("foo", 12345); + m.put("bar", "999"); + m.put("alt", "someval"); + + TestInterface ti = converter.convert(m).to(TestInterface.class); + assertEquals("12345", ti.getFoo()); + assertEquals(999, ti.getbar()); + } + + @SuppressWarnings("rawtypes") + @Test + public void testMapToInterface2() { + Map m = new HashMap<>(); + + TestInterface ti = converter.convert(m).to(TestInterface.class); + assertNull(ti.getFoo()); + assertEquals(0, ti.getbar()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testCopyMap() { + Object obj = new Object(); + Map m = new HashMap<>(); + m.put("key", obj); + Map cm = converter.convert(m).to(Map.class); + assertNotSame(m, cm); + assertSame(m.get("key"), cm.get("key")); + } + + interface TestInterface { + String getFoo(); + int getbar(); + } } Added: felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java?rev=1739734&view=auto ============================================================================== --- felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java (added) +++ felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterServiceTest.java Mon Apr 18 10:31:25 2016 @@ -0,0 +1,122 @@ +/* + * 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.apache.felix.converter.impl; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ConverterServiceTest { + private ConverterService cs; + + @Before + public void setUp() { + cs = new ConverterService(); + } + + @After + public void tearDown() { + cs = null; + } + + @Test + public void testUUIDConversion() { + ConverterService cs = new ConverterService(); + UUID uuid = UUID.randomUUID(); + String s = cs.convert(uuid).to(String.class); + assertTrue("UUID should be something", s.length() > 0); + UUID uuid2 = cs.convert(s).to(UUID.class); + assertEquals(uuid, uuid2); + } + + @Test + public void testPatternConversion() { + String p = "\\S*"; + Pattern pattern = cs.convert(p).to(Pattern.class); + Matcher matcher = pattern.matcher("hi"); + assertTrue(matcher.matches()); + String p2 = cs.convert(pattern).to(String.class); + assertEquals(p, p2); + } + + @Test + public void testLocalDateTime() { + LocalDateTime ldt = LocalDateTime.now(); + String s = cs.convert(ldt).to(String.class); + assertTrue(s.length() > 0); + LocalDateTime ldt2 = cs.convert(s).to(LocalDateTime.class); + assertEquals(ldt, ldt2); + } + + @Test + public void testLocalDate() { + LocalDate ld = LocalDate.now(); + String s = cs.convert(ld).to(String.class); + assertTrue(s.length() > 0); + LocalDate ld2 = cs.convert(s).to(LocalDate.class); + assertEquals(ld, ld2); + } + + @Test + public void testLocalTime() { + LocalTime lt = LocalTime.now(); + String s = cs.convert(lt).to(String.class); + assertTrue(s.length() > 0); + LocalTime lt2 = cs.convert(s).to(LocalTime.class); + assertEquals(lt, lt2); + } + + @Test + public void testOffsetDateTime() { + OffsetDateTime ot = OffsetDateTime.now(); + String s = cs.convert(ot).to(String.class); + assertTrue(s.length() > 0); + OffsetDateTime ot2 = cs.convert(s).to(OffsetDateTime.class); + assertEquals(ot, ot2); + } + + @Test + public void testOffsetTime() { + OffsetTime ot = OffsetTime.now(); + String s = cs.convert(ot).to(String.class); + assertTrue(s.length() > 0); + OffsetTime ot2 = cs.convert(s).to(OffsetTime.class); + assertEquals(ot, ot2); + } + + @Test + public void testZonedDateTime() { + ZonedDateTime zdt = ZonedDateTime.now(); + String s = cs.convert(zdt).to(String.class); + assertTrue(s.length() > 0); + ZonedDateTime zdt2 = cs.convert(s).to(ZonedDateTime.class); + assertEquals(zdt, zdt2); + } +} Modified: felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java URL: http://svn.apache.org/viewvc/felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java?rev=1739734&r1=1739733&r2=1739734&view=diff ============================================================================== --- felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java (original) +++ felix/trunk/converter/src/test/java/org/apache/felix/converter/impl/ConverterTest.java Mon Apr 18 10:31:25 2016 @@ -33,7 +33,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.osgi.service.converter.Adapter; -import org.osgi.service.converter.Converter; import org.osgi.service.converter.TypeReference; import static org.junit.Assert.assertArrayEquals; @@ -44,11 +43,11 @@ import static org.junit.Assert.assertSam import static org.junit.Assert.assertTrue; public class ConverterTest { - private Converter converter; + private ConverterService converter; @Before public void setUp() { - converter = new ConverterImpl(); + converter = new ConverterService(); } @After @@ -77,6 +76,7 @@ public class ConverterTest { assertTrue(converter.convert("TRUE").to(boolean.class)); assertTrue(converter.convert('x').to(boolean.class)); assertTrue(converter.convert(Long.MIN_VALUE).to(boolean.class)); + assertTrue(converter.convert(72).to(boolean.class)); assertFalse(converter.convert("false").to(boolean.class)); assertFalse(converter.convert("bleh").to(boolean.class)); assertFalse(converter.convert((char) 0).to(boolean.class)); @@ -86,6 +86,7 @@ public class ConverterTest { // Converstions to integer assertEquals(Integer.valueOf(123), converter.convert("123").to(int.class)); assertEquals(1, (int) converter.convert(true).to(int.class)); + assertEquals(0, (int) converter.convert(false).to(int.class)); // Conversions to Class assertEquals(BigDecimal.class, converter.convert("java.math.BigDecimal").to(Class.class));