You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@batchee.apache.org by st...@apache.org on 2015/11/09 21:34:47 UTC
incubator-batchee git commit: BATCHEE-66 add support for joda,
java8 time and enums
Repository: incubator-batchee
Updated Branches:
refs/heads/master 1a0259c6f -> 8d89ac8cd
BATCHEE-66 add support for joda, java8 time and enums
Project: http://git-wip-us.apache.org/repos/asf/incubator-batchee/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-batchee/commit/8d89ac8c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-batchee/tree/8d89ac8c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-batchee/diff/8d89ac8c
Branch: refs/heads/master
Commit: 8d89ac8cde1730d249290ea0e3697159e77b0f60
Parents: 1a0259c
Author: Mark Struberg <st...@apache.org>
Authored: Mon Nov 9 21:17:03 2015 +0100
Committer: Mark Struberg <st...@apache.org>
Committed: Mon Nov 9 21:17:03 2015 +0100
----------------------------------------------------------------------
jbatch/pom.xml | 4 +
.../data/DefaultDataRepresentationService.java | 161 +++++++++++++++++--
.../DefaultDataRepresentationServiceTest.java | 40 ++++-
pom.xml | 9 ++
4 files changed, 197 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/8d89ac8c/jbatch/pom.xml
----------------------------------------------------------------------
diff --git a/jbatch/pom.xml b/jbatch/pom.xml
index 8b0eac2..a746164 100644
--- a/jbatch/pom.xml
+++ b/jbatch/pom.xml
@@ -85,6 +85,10 @@
<artifactId>derby</artifactId>
</dependency>
<dependency>
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>openejb-core</artifactId>
<version>4.7.2</version>
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/8d89ac8c/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java
----------------------------------------------------------------------
diff --git a/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java b/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java
index 6056ded..7453059 100644
--- a/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java
+++ b/jbatch/src/main/java/org/apache/batchee/container/services/data/DefaultDataRepresentationService.java
@@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
+import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
@@ -44,13 +45,14 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
public static final String BATCHEE_DATA_PREFIX = "BatchEE_data" + BATCHEE_SPLIT_TOKEN;
- private Charset UTF8_CHARSET = StandardCharsets.UTF_8;
+
+ private static final Charset UTF8_CHARSET = StandardCharsets.UTF_8;
private static final Logger LOGGER = Logger.getLogger(DefaultDataRepresentationService.class.getName());
+
@Override
public void init(Properties batchConfig) {
- // nothing to do
}
@Override
@@ -64,6 +66,18 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
serialValue = convertJava7DateTypes(dataObject);
}
if (serialValue == null) {
+ serialValue = convertJava8DateTypes(dataObject);
+ }
+ if (serialValue == null) {
+ serialValue = convertJodaDateTypes(dataObject);
+ }
+ if (serialValue == null) {
+ serialValue = convertCustomEnumTypes(dataObject);
+ }
+ if (serialValue == null) {
+ serialValue = convertCustomTypes(dataObject);
+ }
+ if (serialValue == null) {
// as last resort we do a simple java serialisation
serialValue = convertSerializableObjectTypes(dataObject);
}
@@ -89,6 +103,18 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
if (data == null) {
data = convertBackJava7DateTypes(typeVal, valueVal);
}
+ if (data == null) {
+ data = convertBackJava8DateTypes(typeVal, valueVal);
+ }
+ if (data == null) {
+ data = convertBackJodaDateTypes(typeVal, valueVal);
+ }
+ if (data == null) {
+ data = convertBackCustomEnumTypes(typeVal, valueVal);
+ }
+ if (data == null) {
+ data = convertBackCustomTypes(typeVal, valueVal);
+ }
}
@@ -106,12 +132,45 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
return data;
}
+ private <T> byte[] convertCustomEnumTypes(T dataObject) {
+ if (dataObject instanceof Enum) {
+ return toBatchEeData(dataObject.getClass(), ((Enum) dataObject).name());
+ }
+ return null;
+ }
+
+ private <T> T convertBackCustomEnumTypes(String typeVal, String valueVal) {
+ try {
+ Class typeClass = getClassLoader().loadClass(typeVal);
+ if (typeClass.isEnum()) {
+ return (T) Enum.valueOf(typeClass, valueVal);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Cannot convert back BatchEE data: " + valueVal + " of Enum type " + typeVal);
+ }
+ return null;
+ }
+
+ /**
+ * This is an extension point for other serialisation algorithms.
+ */
+ protected <T> byte[] convertCustomTypes(T dataObject) {
+ return null;
+ }
+
+ /**
+ * This is an extension point for other serialsation algorithms.
+ */
+ private <T> T convertBackCustomTypes(String typeVal, String valueVal) {
+ return null;
+ }
+
/**
* This method converts java native types to a 'nice' string representation
* which will be stored in the database.
* @return the String representation or {@code null} if the dataObject was not a native Java type
*/
- private <T> byte[] convertJavaNativeTypes(T dataObject) {
+ protected <T> byte[] convertJavaNativeTypes(T dataObject) {
// convert int, Integer, etc
if (dataObject instanceof Integer ||
dataObject instanceof String ||
@@ -125,7 +184,7 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
return null;
}
- private <T> T convertBackJavaNativeTypes(String typeVal, String value) {
+ protected <T> T convertBackJavaNativeTypes(String typeVal, String value) {
if (Integer.class.getName().equals(typeVal)) {
return (T) Integer.valueOf(value);
}
@@ -156,7 +215,7 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
* <li>java.sql.Timestamp</li>
* </ul>
*/
- private <T> byte[] convertJava7DateTypes(T dataObject) {
+ protected <T> byte[] convertJava7DateTypes(T dataObject) {
if (dataObject.getClass().equals(Date.class)) {
return toBatchEeData(Date.class, getSimpleDateFormat().format((Date) dataObject));
}
@@ -170,7 +229,7 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
return null;
}
- private <T> T convertBackJava7DateTypes(String typeVal, String valueVal) {
+ protected <T> T convertBackJava7DateTypes(String typeVal, String valueVal) {
if (Date.class.getName().equals(typeVal)) {
try {
return (T) getSimpleDateFormat().parse(valueVal);
@@ -194,49 +253,123 @@ public class DefaultDataRepresentationService implements DataRepresentationServi
return null;
}
+ private <T> byte[] convertJodaDateTypes(T dataObject) {
+ String className = dataObject.getClass().getName();
+ if (className.equals("org.joda.time.LocalDate") ||
+ className.equals("org.joda.time.LocalDateTime") ||
+ className.equals("org.joda.time.LocalTime")) {
+ // joda date API does the right thing on toString
+ return toBatchEeData(dataObject.getClass(), dataObject.toString());
+ }
+ return null;
+ }
+ private <T> T convertBackJodaDateTypes(String typeVal, String valueVal) {
+ if (typeVal.equals("org.joda.time.LocalDate") ||
+ typeVal.equals("org.joda.time.LocalDateTime") ||
+ typeVal.equals("org.joda.time.LocalTime")) {
+ return (T) invokeStaticMethod(typeVal, "parse", String.class, valueVal);
+ }
+ return null;
+ }
+
+ private <T> byte[] convertJava8DateTypes(T dataObject) {
+ String className = dataObject.getClass().getName();
+ if (className.equals("java.time.LocalDate") ||
+ className.equals("java.time.LocalDateTime") ||
+ className.equals("java.time.LocalTime")) {
+ // joda date API does the right thing on toString
+ return toBatchEeData(dataObject.getClass(), dataObject.toString());
+ }
+ return null;
+ }
+
+ private <T> T convertBackJava8DateTypes(String typeVal, String valueVal) {
+ if (typeVal.equals("java.time.LocalDate") ||
+ typeVal.equals("java.time.LocalDateTime") ||
+ typeVal.equals("java.time.LocalTime")) {
+ return (T) invokeStaticMethod(typeVal, "parse", CharSequence.class, valueVal);
+ }
+ return null;
+ }
+
+ protected Object invokeStaticMethod(String typeVal, String methodName, Class paramType, String valueVal) {
+ try {
+ Class<?> typeClass = getClassLoader().loadClass(typeVal);
+ Method method = typeClass.getMethod(methodName, paramType);
+ return method.invoke(null, valueVal);
+ } catch (ReflectiveOperationException e) {
+ throw new BatchContainerServiceException("Cannot convert data [" + valueVal + "] of type [" + typeVal + "]", e );
+ }
+ }
/**
* This is the default operation if no other way to serialise the data was used
*/
- private <T> byte[] convertSerializableObjectTypes(T dataObject) {
+ protected <T> byte[] convertSerializableObjectTypes(T dataObject) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(dataObject);
- oos.close();
} catch (IOException e) {
throw new BatchContainerServiceException("Cannot convert data for [" + dataObject.toString() + "]");
+ } finally {
+ if (oos != null) {
+ try {
+ oos.close();
+ } catch (IOException e) {
+ // meh give up...
+ }
+ }
}
return baos.toByteArray();
}
- private <T> T convertBackSerializableObjectTypes(byte[] internalRepresentation) {
+
+ protected <T> T convertBackSerializableObjectTypes(byte[] internalRepresentation) {
final ByteArrayInputStream readerChkptBA = new ByteArrayInputStream(internalRepresentation);
- TCCLObjectInputStream readerOIS;
+ TCCLObjectInputStream readerOIS = null;
try {
// need to use the TCCL in case the batch is in a webapp but jbatch runtime is provided in a parent ClassLoader
readerOIS = new TCCLObjectInputStream(readerChkptBA);
T instance = (T) readerOIS.readObject();
- readerOIS.close();
return instance;
} catch (final Exception ex) {
return null;
+ } finally {
+ if (readerOIS != null) {
+ try {
+ readerOIS.close();
+ } catch (IOException e) {
+ // meh give up...
+ }
+ }
}
}
- private byte[] toBatchEeData(Class<?> type, String stringRepresentation) {
+ protected byte[] toBatchEeData(Class<?> type, String stringRepresentation) {
return (BATCHEE_DATA_PREFIX + type.getName() + BATCHEE_SPLIT_TOKEN + stringRepresentation).getBytes(UTF8_CHARSET);
}
- private SimpleDateFormat getSimpleDateFormat() {
+ protected ClassLoader getClassLoader() {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ if (cl == null) {
+ cl = this.getClass().getClassLoader();
+ }
+ return cl;
+ }
+
+ protected SimpleDateFormat getSimpleDateFormat() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
return sdf;
}
- private SimpleDateFormat getTimestampDateFormat() {
+ /**
+ * Attention: The nanos must get concatenated separately as there is no formatter for nanos!
+ */
+ protected SimpleDateFormat getTimestampDateFormat() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
return sdf;
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/8d89ac8c/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java
----------------------------------------------------------------------
diff --git a/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java b/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java
index a60f554..e5fba15 100644
--- a/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java
+++ b/jbatch/src/test/java/org/apache/batchee/test/data/DefaultDataRepresentationServiceTest.java
@@ -17,6 +17,7 @@
package org.apache.batchee.test.data;
import java.io.Serializable;
+import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
@@ -32,6 +33,9 @@ import javax.batch.runtime.StepExecution;
import org.apache.batchee.container.services.data.DefaultDataRepresentationService;
import org.apache.batchee.spi.DataRepresentationService;
import org.apache.batchee.util.Batches;
+import org.joda.time.LocalDate;
+import org.joda.time.LocalDateTime;
+import org.joda.time.LocalTime;
import org.junit.Assert;
import org.junit.Test;
import static org.testng.Assert.assertEquals;
@@ -72,7 +76,15 @@ public class DefaultDataRepresentationServiceTest {
@Test
public void testJavaCustomEnum() {
- //X TODO
+ assertRoundTripEquals(MySampleEnum.VALUE1, true);
+ assertRoundTripEquals(MySampleEnum.VALUE2, true);
+ assertRoundTripEquals(MySampleEnum.ANOTHER_VALUE, true);
+ }
+
+ public enum MySampleEnum {
+ VALUE1,
+ VALUE2,
+ ANOTHER_VALUE
}
@Test
@@ -102,12 +114,32 @@ public class DefaultDataRepresentationServiceTest {
@Test
public void testJava8DateTimeViaReflection() {
- //X TODO
+ Object java8LocalDate = createJava8datetype("java.time.LocalDate");
+ Object java8LocalTime = createJava8datetype("java.time.LocalTime");
+ Object java8LocalDateTime = createJava8datetype("java.time.LocalDateTime");
+ if (java8LocalDate != null) {
+ assertRoundTripEquals(java8LocalDate, true);
+ assertRoundTripEquals(java8LocalTime, true);
+ assertRoundTripEquals(java8LocalDateTime, true);
+ }
+ }
+
+ private Object createJava8datetype(String className) {
+ try {
+ Class<?> clazz = Class.forName(className);
+ Method now = clazz.getMethod("now");
+ return now.invoke(null);
+ } catch (ReflectiveOperationException e) {
+ // all fine, we are just not running on java8
+ }
+ return null;
}
@Test
public void testJodaDateTimeViaReflection() {
- //X TODO
+ assertRoundTripEquals(LocalDate.now(), true);
+ assertRoundTripEquals(LocalDateTime.now(), true);
+ assertRoundTripEquals(LocalTime.now(), true);
}
@Test
@@ -190,6 +222,7 @@ public class DefaultDataRepresentationServiceTest {
}
+ @SuppressWarnings("unused")
public static class DummyReaderWithCheckpoint extends AbstractItemReader {
@@ -213,6 +246,7 @@ public class DefaultDataRepresentationServiceTest {
}
}
+ @SuppressWarnings("unused")
public static class DummyWriterWithCheckpoint extends AbstractItemWriter {
private Integer lastCount = null;
http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/8d89ac8c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index be788b6..0015acf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,6 +42,7 @@
<atinject.version>1.0</atinject.version>
<batch-api.version>1.0</batch-api.version>
<jackson.version>2.2.2</jackson.version>
+ <jodatime.version>2.8.1</jodatime.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<batchee.scmPubUrl>https://svn.apache.org/repos/asf/incubator/batchee/site</batchee.scmPubUrl>
<batchee.scmPubCheckoutDirectory>${basedir}/.site-content</batchee.scmPubCheckoutDirectory>
@@ -158,6 +159,14 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <!-- We have optional support for joda time IF it is available on the classpath -->
+ <groupId>joda-time</groupId>
+ <artifactId>joda-time</artifactId>
+ <version>${jodatime.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<!-- Testing libraries -->
<dependency> <!-- TCK and default tests -->
<groupId>org.testng</groupId>