You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@batchee.apache.org by rm...@apache.org on 2015/11/24 12:08:23 UTC
incubator-batchee git commit: better coercing for commons csv mapper
Repository: incubator-batchee
Updated Branches:
refs/heads/master 7dc84fcb6 -> 6047c395c
better coercing for commons csv mapper
Project: http://git-wip-us.apache.org/repos/asf/incubator-batchee/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-batchee/commit/6047c395
Tree: http://git-wip-us.apache.org/repos/asf/incubator-batchee/tree/6047c395
Diff: http://git-wip-us.apache.org/repos/asf/incubator-batchee/diff/6047c395
Branch: refs/heads/master
Commit: 6047c395cd4bcca76bbefa6a44c5ca94135bb066
Parents: 7dc84fc
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Tue Nov 24 12:08:20 2015 +0100
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Tue Nov 24 12:08:20 2015 +0100
----------------------------------------------------------------------
extensions/commons-csv/pom.xml | 7 +
.../batchee/csv/mapper/CoercingConverter.java | 21 +++
.../batchee/csv/mapper/DefaultMapper.java | 25 +++-
.../apache/batchee/csv/mapper/Primitives.java | 146 ++++++++++++-------
.../batchee/csv/mapper/XBeanConverter.java | 37 +++++
.../batchee/csv/mapper/PrimitivesTest.java | 54 +++++++
6 files changed, 236 insertions(+), 54 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/6047c395/extensions/commons-csv/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/commons-csv/pom.xml b/extensions/commons-csv/pom.xml
index c0096fc..96fb793 100644
--- a/extensions/commons-csv/pom.xml
+++ b/extensions/commons-csv/pom.xml
@@ -42,5 +42,12 @@
<artifactId>commons-csv</artifactId>
<version>1.2</version>
</dependency>
+
+ <dependency>
+ <groupId>org.apache.xbean</groupId>
+ <artifactId>xbean-reflect</artifactId>
+ <version>4.4</version>
+ <optional>true</optional>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/6047c395/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/CoercingConverter.java
----------------------------------------------------------------------
diff --git a/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/CoercingConverter.java b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/CoercingConverter.java
new file mode 100644
index 0000000..66d5a86
--- /dev/null
+++ b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/CoercingConverter.java
@@ -0,0 +1,21 @@
+/*
+ * 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.batchee.csv.mapper;
+
+public interface CoercingConverter {
+ Object valueFor(Class<?> type, String value);
+}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/6047c395/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/DefaultMapper.java
----------------------------------------------------------------------
diff --git a/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/DefaultMapper.java b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/DefaultMapper.java
index 93e59b7..b7de7d1 100644
--- a/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/DefaultMapper.java
+++ b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/DefaultMapper.java
@@ -29,6 +29,7 @@ import java.util.TreeMap;
public class DefaultMapper<T> implements CsvReaderMapper<T>, CsvWriterMapper<T> {
private final Class<T> type;
+ private final CoercingConverter coercingConverter;
private final SortedMap<Integer, Field> fieldByPosition = new TreeMap<Integer, Field>();
private final SortedMap<String, Field> fieldByName = new TreeMap<String, Field>();
@@ -36,7 +37,12 @@ public class DefaultMapper<T> implements CsvReaderMapper<T>, CsvWriterMapper<T>
private final int maxIndex;
public DefaultMapper(final Class<T> type) {
+ this(type, loadConverter());
+ }
+
+ protected DefaultMapper(final Class<T> type, final CoercingConverter coercingConverter) {
this.type = type;
+ this.coercingConverter = coercingConverter;
int higherIdx = -1;
@@ -137,10 +143,23 @@ public class DefaultMapper<T> implements CsvReaderMapper<T>, CsvWriterMapper<T>
if (String.class == type) {
return value;
}
- final Object primVal = Primitives.valueFor(type, value);
- if (primVal != null) {
- return primVal;
+
+ if (coercingConverter != null) {
+ final Object val = coercingConverter.valueFor(type, value);
+ if (val != null) {
+ return val;
+ }
}
+
throw new IllegalArgumentException("Unsupported type " + type);
}
+
+ private static CoercingConverter loadConverter() {
+ try {
+ Thread.currentThread().getContextClassLoader().loadClass("org.apache.xbean.propertyeditor.PropertyEditors");
+ return XBeanConverter.INSTANCE;
+ } catch (ClassNotFoundException e) {
+ return Primitives.INSTANCE;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/6047c395/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/Primitives.java
----------------------------------------------------------------------
diff --git a/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/Primitives.java b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/Primitives.java
index 3f1ea59..c550158 100644
--- a/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/Primitives.java
+++ b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/Primitives.java
@@ -16,60 +16,68 @@
*/
package org.apache.batchee.csv.mapper;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
-public enum Primitives {
- BooleanType(Boolean.class, boolean.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return Boolean.parseBoolean(o);
- }
- }),
- IntegerType(Integer.class, int.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return Integer.parseInt(o);
- }
- }),
- ShortType(Short.class, short.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return Short.parseShort(o);
- }
- }),
- LongType(Long.class, long.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return Long.parseLong(o);
- }
- }),
- ByteType(Byte.class, byte.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return Byte.parseByte(o);
- }
- }),
- FloatType(Float.class, float.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return Float.parseFloat(o);
- }
- }),
- DoubleType(Double.class, double.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return Double.parseDouble(o);
- }
- }),
- CharacterType(Character.class, char.class, new Converter() {
- @Override
- public Object convert(final String o) {
- return o.length() == 0 ? null : o.charAt(0);
- }
- });
+public class Primitives implements CoercingConverter {
+ static {
+ register(Boolean.class, boolean.class, false, new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return Boolean.parseBoolean(o);
+ }
+ });
+ register(Integer.class, int.class, (int) 0, new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return Integer.parseInt(o);
+ }
+ });
+ register(Short.class, short.class, (short) 0, new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return Short.parseShort(o);
+ }
+ });
+ register(Long.class, long.class, 0L, new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return Long.parseLong(o);
+ }
+ });
+ register(Byte.class, byte.class, (byte) 0, new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return Byte.parseByte(o);
+ }
+ });
+ register(Float.class, float.class, 0.f, new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return Float.parseFloat(o);
+ }
+ });
+ register(Double.class, double.class, 0., new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return Double.parseDouble(o);
+ }
+ });
+ register(Character.class, char.class, (char) 0, new Converter() {
+ @Override
+ public Object convert(final String o) {
+ return o.length() == 0 ? null : o.charAt(0);
+ }
+ });
+ }
+
+ public static final CoercingConverter INSTANCE = new Primitives();
private static final class Mapping {
+ private static final Map<Class<?>, Method> PRIMITIVES = new HashMap<Class<?>, Method>();
+ private static final Map<Class<?>, Object> PRIMITIVE_DEFAULTS = new HashMap<Class<?>, Object>();
private static final Map<Class<?>, Class<?>> WRAPPERS = new HashMap<Class<?>, Class<?>>();
private static final Map<Class<?>, Converter> CONVERTERS = new HashMap<Class<?>, Converter>();
@@ -82,20 +90,56 @@ public enum Primitives {
Object convert(String o);
}
- Primitives(final Class<?> wrapper, final Class<?> primitive, final Converter converter) {
+ public static Object primitiveDefaultValue(final Class<?> type) {
+ return Mapping.PRIMITIVE_DEFAULTS.get(type);
+ }
+
+ private static void register(final Class<?> wrapper, final Class<?> primitive, final Object defaultValue, final Converter converter) {
Mapping.WRAPPERS.put(wrapper, primitive);
Mapping.CONVERTERS.put(wrapper, converter);
+ Mapping.PRIMITIVE_DEFAULTS.put(primitive, defaultValue);
+ if (wrapper != Character.class) {
+ try {
+ Mapping.PRIMITIVES.put(primitive, wrapper.getMethod("valueOf", String.class));
+ } catch (final NoSuchMethodException e) {
+ throw new IllegalStateException(e);
+ }
+ }
}
- public static Object valueFor(final Class<?> type, final String value) {
+ @Override
+ public Object valueFor(final Class<?> type, final String value) {
+ final Method valueOf = Mapping.PRIMITIVES.get(type);
+ if (valueOf != null) {
+ if (value == null || value.trim().isEmpty()) {
+ return Mapping.PRIMITIVE_DEFAULTS.get(type);
+ }
+
+ try {
+ return valueOf.invoke(null, value);
+ } catch (final IllegalAccessException e) {
+ throw new IllegalArgumentException(e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException(e.getCause());
+ }
+ } else if (char.class == type) {
+ if (value == null || value.trim().isEmpty()) {
+ return Mapping.PRIMITIVE_DEFAULTS.get(type);
+ }
+ return value.charAt(0);
+ }
+
if (value == null) {
return null;
}
+
final Class<?> currentType = value.getClass();
final Class<?> primitive = Mapping.WRAPPERS.get(currentType);
if (primitive != null && type == primitive) {
return Mapping.CONVERTERS.get(currentType).convert(value);
}
+
+
return null;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/6047c395/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/XBeanConverter.java
----------------------------------------------------------------------
diff --git a/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/XBeanConverter.java b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/XBeanConverter.java
new file mode 100644
index 0000000..50e10cd
--- /dev/null
+++ b/extensions/commons-csv/src/main/java/org/apache/batchee/csv/mapper/XBeanConverter.java
@@ -0,0 +1,37 @@
+/*
+ * 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.batchee.csv.mapper;
+
+import org.apache.xbean.propertyeditor.PropertyEditors;
+
+public final class XBeanConverter implements CoercingConverter {
+ public static final CoercingConverter INSTANCE = new XBeanConverter();
+
+ @Override
+ public Object valueFor(final Class<?> type, final String value) {
+ if (value == null || value.isEmpty()) {
+ final Object def = Primitives.primitiveDefaultValue(type);
+ if (def != null) {
+ return def;
+ }
+ }
+ if (value == null) {
+ return null;
+ }
+ return PropertyEditors.canConvert(type) ? PropertyEditors.getValue(type, value) : null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/6047c395/extensions/commons-csv/src/test/java/org/apache/batchee/csv/mapper/PrimitivesTest.java
----------------------------------------------------------------------
diff --git a/extensions/commons-csv/src/test/java/org/apache/batchee/csv/mapper/PrimitivesTest.java b/extensions/commons-csv/src/test/java/org/apache/batchee/csv/mapper/PrimitivesTest.java
new file mode 100644
index 0000000..971e282
--- /dev/null
+++ b/extensions/commons-csv/src/test/java/org/apache/batchee/csv/mapper/PrimitivesTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.batchee.csv.mapper;
+
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Theories.class)
+public class PrimitivesTest {
+ @DataPoints
+ public static CoercingConverter[] converters() {
+ return new CoercingConverter[]{ new Primitives(), new XBeanConverter() };
+ }
+
+ @Theory
+ public void defaultValues(final CoercingConverter converter) {
+ assertEquals(0L, converter.valueFor(long.class, ""));
+ assertEquals((short) 0, converter.valueFor(short.class, ""));
+ assertEquals(0, converter.valueFor(int.class, ""));
+ assertEquals((byte) 0, converter.valueFor(byte.class, ""));
+ assertEquals((char) 0, converter.valueFor(char.class, ""));
+ assertEquals(0.f, converter.valueFor(float.class, ""));
+ assertEquals(0., converter.valueFor(double.class, ""));
+ }
+
+ @Theory
+ public void primitives(final CoercingConverter converter) {
+ assertEquals(1L, converter.valueFor(long.class, "1"));
+ assertEquals((short) 1, converter.valueFor(short.class, "1"));
+ assertEquals(1, converter.valueFor(int.class, "1"));
+ assertEquals((byte) 1, converter.valueFor(byte.class, "1"));
+ assertEquals(1.f, converter.valueFor(float.class, "1"));
+ assertEquals(1., converter.valueFor(double.class, "1"));
+ assertEquals('1', converter.valueFor(char.class, "1"));
+ }
+}