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 2013/11/05 08:39:17 UTC

[40/62] importing batchee from github - a fork from the IBm RI

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJSonWriter.java
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJSonWriter.java b/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJSonWriter.java
new file mode 100644
index 0000000..a2b96c7
--- /dev/null
+++ b/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJSonWriter.java
@@ -0,0 +1,117 @@
+/*
+ * 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.jackson;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.batchee.extras.transaction.TransactionalWriter;
+
+import javax.batch.api.BatchProperty;
+import javax.batch.api.chunk.ItemWriter;
+import javax.batch.operations.BatchRuntimeException;
+import javax.inject.Inject;
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+
+public class JacksonJSonWriter implements ItemWriter {
+    @Inject
+    @BatchProperty
+    private String file;
+
+    @Inject
+    @BatchProperty
+    private String encoding;
+
+    @Inject
+    @BatchProperty
+    private String configuration;
+
+    @Inject
+    @BatchProperty
+    private String skipRoot;
+
+    @Inject
+    @BatchProperty
+    private String fieldNameGeneratorClass;
+
+    private JsonGenerator generator;
+    private TransactionalWriter writer;
+    private FieldNameGenerator fieldNameGenerator = null;
+
+    @Override
+    public void open(final Serializable checkpoint) throws Exception {
+        final File outputFile = new File(file);
+        if (!outputFile.getParentFile().exists() && !outputFile.getParentFile().mkdirs()) {
+            throw new BatchRuntimeException("Can't create " + outputFile.getAbsolutePath());
+        }
+
+        final ObjectMapper mapper = Jacksons.newMapper(configuration);
+
+        writer = new TransactionalWriter(outputFile, encoding, checkpoint);
+        generator = mapper.getFactory().createGenerator(writer);
+        if (fieldNameGeneratorClass != null) {
+            if ("default".equals(fieldNameGeneratorClass)) {
+                fieldNameGenerator = new DefaultFieldNameGenerator();
+            } else {
+                fieldNameGenerator = FieldNameGenerator.class.cast(Thread.currentThread().getContextClassLoader().loadClass(fieldNameGeneratorClass).newInstance());
+            }
+        }
+
+        if (useGlobalWrapper()) {
+            if (fieldNameGenerator != null) {
+                generator.writeStartObject();
+            } else {
+                generator.writeStartArray();
+            }
+        }
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (generator != null) {
+            if (useGlobalWrapper()) {
+                if (fieldNameGenerator != null) {
+                    generator.writeEndObject();
+                } else {
+                    generator.writeEndArray();
+                }
+            }
+            generator.close();
+        }
+    }
+
+    @Override
+    public void writeItems(final List<Object> items) throws Exception {
+        for (final Object o : items) {
+            if (fieldNameGenerator != null) {
+                generator.writeFieldName(fieldNameGenerator.nextName());
+            }
+            generator.writeObject(o);
+        }
+        writer.flush();
+    }
+
+    @Override
+    public Serializable checkpointInfo() throws Exception {
+        return writer.position();
+    }
+
+    private boolean useGlobalWrapper() {
+        return skipRoot == null || !"true".equalsIgnoreCase(skipRoot);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJsonReader.java
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJsonReader.java b/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJsonReader.java
new file mode 100644
index 0000000..7fb07fd
--- /dev/null
+++ b/extensions/jackson/src/main/java/org/apache/batchee/jackson/JacksonJsonReader.java
@@ -0,0 +1,91 @@
+/*
+ * 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.jackson;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.batchee.extras.transaction.CountedReader;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+import java.io.File;
+import java.io.Serializable;
+
+public class JacksonJsonReader extends CountedReader {
+    @Inject
+    @BatchProperty
+    private String file;
+
+    @Inject
+    @BatchProperty
+    private String type;
+
+    @Inject
+    @BatchProperty
+    private String configuration;
+
+    @Inject
+    @BatchProperty
+    private String skipRoot;
+
+    private JsonParser parser;
+    private Class<?> clazz;
+    private JsonToken end = null;
+
+    @Override
+    public void open(final Serializable checkpoint) throws Exception {
+        super.open(checkpoint);
+
+        final ObjectMapper mapper = Jacksons.newMapper(configuration);
+        parser = mapper.getFactory().createParser(new File(file));
+        if (type != null) {
+            clazz = Thread.currentThread().getContextClassLoader().loadClass(type);
+        } else {
+            clazz = null;
+        }
+
+        if (skipRoot == null || "true".equalsIgnoreCase(skipRoot)) {
+            final JsonToken token = parser.nextToken();
+            if (token == JsonToken.START_ARRAY) {
+                end = JsonToken.END_ARRAY;
+            } else {
+                end = JsonToken.END_OBJECT;
+            }
+        }
+    }
+
+    @Override
+    protected Object doRead() throws Exception {
+        JsonToken token;
+        do {
+            token = parser.nextToken();
+        } while ((token != JsonToken.START_OBJECT && token != end) || (end == null && (token == JsonToken.END_ARRAY || token == JsonToken.END_OBJECT)));
+
+        if (clazz == null) {
+            parser.readValueAsTree();
+        }
+        return parser.readValueAs(clazz);
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (parser != null) {
+            parser.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/main/java/org/apache/batchee/jackson/Jacksons.java
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/main/java/org/apache/batchee/jackson/Jacksons.java b/extensions/jackson/src/main/java/org/apache/batchee/jackson/Jacksons.java
new file mode 100644
index 0000000..74ff0f2
--- /dev/null
+++ b/extensions/jackson/src/main/java/org/apache/batchee/jackson/Jacksons.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jackson;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public final class Jacksons {
+    public static ObjectMapper newMapper(final String config) {
+        final ObjectMapper mapper = new ObjectMapper();
+        if (config != null) {
+            final String deserializationName = DeserializationFeature.class.getSimpleName();
+            final String serializationName = SerializationFeature.class.getSimpleName();
+            final String mapperName = MapperFeature.class.getSimpleName();
+            for (final String conf : config.split(",")) {
+                final String[] parts = conf.split("=");
+                parts[0] = parts[0].trim();
+                parts[1] = parts[1].trim();
+
+                if (parts[0].startsWith(deserializationName)) {
+                    mapper.configure(DeserializationFeature.valueOf(parts[0].substring(deserializationName.length() + 1)), Boolean.parseBoolean(parts[1]));
+                } else if (parts[0].startsWith(serializationName)) {
+                    mapper.configure(SerializationFeature.valueOf(parts[0].substring(serializationName.length() + 1)), Boolean.parseBoolean(parts[1]));
+                } else if (parts[0].startsWith(mapperName)) {
+                    mapper.configure(MapperFeature.valueOf(parts[0].substring(mapperName.length() + 1)), Boolean.parseBoolean(parts[1]));
+                } else {
+                    throw new IllegalArgumentException("Ignored config: " + conf);
+                }
+            }
+        }
+        return mapper;
+    }
+
+    private Jacksons() {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/main/resources/META-INF/batchee.xml
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/main/resources/META-INF/batchee.xml b/extensions/jackson/src/main/resources/META-INF/batchee.xml
new file mode 100644
index 0000000..24d480d
--- /dev/null
+++ b/extensions/jackson/src/main/resources/META-INF/batchee.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<batch-artifacts xmlns="http://xmlns.jcp.org/xml/ns/javaee">
+  <ref id="jacksonJSonReader" class="org.apache.batchee.jackson.JacksonJsonReader" />
+  <ref id="jacksonJSonWriter" class="org.apache.batchee.jackson.JacksonJSonWriter" />
+</batch-artifacts>

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJSonWriterTest.java
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJSonWriterTest.java b/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJSonWriterTest.java
new file mode 100644
index 0000000..8894892
--- /dev/null
+++ b/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJSonWriterTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.jackson;
+
+import org.apache.batchee.jackson.bean.Record;
+import org.apache.batchee.jackson.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemReader;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.io.Serializable;
+import java.util.Properties;
+
+import static org.testng.Assert.assertEquals;
+
+public class JacksonJSonWriterTest {
+    @Test
+    public void write() {
+        final JobOperator operator = BatchRuntime.getJobOperator();
+        Batches.waitForEnd(operator, operator.start("jackson-writer", new Properties()));
+        final String output = IOs.slurp("target/work/jackson-output.json");
+        assertEquals(output.replace("\n", "").replace("\r", "").replace(" ", "").replace("\t", ""),
+                    "[{\"v1\":\"v11\",\"v2\":\"v21\"},{\"v1\":\"v12\",\"v2\":\"v22\"}]");
+    }
+
+    @Test
+    public void writeWithFields() {
+        final JobOperator operator = BatchRuntime.getJobOperator();
+        Batches.waitForEnd(operator, operator.start("jackson-field-writer", new Properties()));
+        final String output = IOs.slurp("target/work/jackson-field-output.json");
+        assertEquals(output.replace("\n", "").replace("\r", "").replace(" ", "").replace("\t", ""),
+            "{\"item1\":{\"v1\":\"v11\",\"v2\":\"v21\"},\"item2\":{\"v1\":\"v12\",\"v2\":\"v22\"}}");
+    }
+
+    public static class Reader implements ItemReader {
+        private int count = 0;
+
+        @Override
+        public void open(final Serializable checkpoint) throws Exception {
+            // no-op
+        }
+
+        @Override
+        public void close() throws Exception {
+            // no-op
+        }
+
+        @Override
+        public Object readItem() throws Exception {
+            if (count++ < 2) {
+                final Record record = new Record();
+                record.setV1("v1" + count);
+                record.setV2("v2" + count);
+                return record;
+            }
+            return null;
+        }
+
+        @Override
+        public Serializable checkpointInfo() throws Exception {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJsonReaderTest.java
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJsonReaderTest.java b/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJsonReaderTest.java
new file mode 100644
index 0000000..99c132f
--- /dev/null
+++ b/extensions/jackson/src/test/java/org/apache/batchee/jackson/JacksonJsonReaderTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.jackson;
+
+import org.apache.batchee.jackson.bean.Record;
+import org.apache.batchee.jackson.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemWriter;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.testng.Assert.assertEquals;
+
+public class JacksonJsonReaderTest {
+    @Test
+    public void read() {
+        IOs.write("target/work/jackson-input.json", "[" +
+            "  {" +
+            "    \"v1\":\"record 1 # field 1\"," +
+            "    \"v2\":\"record 1 # field 2\"" +
+            "  }," +
+            "  {" +
+            "    \"v1\":\"record 2 # field 1\"," +
+            "    \"v2\":\"record 2 # field 2\"" +
+            "  }" +
+            "]");
+
+        final JobOperator operator = BatchRuntime.getJobOperator();
+        Batches.waitForEnd(operator, operator.start("jackson-reader", new Properties()));
+        assertEquals(Writer.ITEMS.size(), 2);
+        for (int i = 1; i < Writer.ITEMS.size() + 1; i++) {
+            final Record record = Writer.ITEMS.get(i - 1);
+            assertEquals("record " + i + " # field 1", record.getV1());
+            assertEquals("record " + i + " # field 2", record.getV2());
+        }
+    }
+
+    public static class Writer implements ItemWriter {
+        public static List<Record> ITEMS = new ArrayList<Record>(2);
+
+        @Override
+        public void open(final Serializable checkpoint) throws Exception {
+            // no-op
+        }
+
+        @Override
+        public void close() throws Exception {
+            // no-op
+        }
+
+        @Override
+        public void writeItems(final List<Object> items) throws Exception {
+            ITEMS.addAll(List.class.cast(items));
+        }
+
+        @Override
+        public Serializable checkpointInfo() throws Exception {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/test/java/org/apache/batchee/jackson/bean/Record.java
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/test/java/org/apache/batchee/jackson/bean/Record.java b/extensions/jackson/src/test/java/org/apache/batchee/jackson/bean/Record.java
new file mode 100644
index 0000000..622c8a9
--- /dev/null
+++ b/extensions/jackson/src/test/java/org/apache/batchee/jackson/bean/Record.java
@@ -0,0 +1,38 @@
+/*
+ * 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.jackson.bean;
+
+public class Record {
+    private String v1;
+    private String v2;
+
+    public String getV1() {
+        return v1;
+    }
+
+    public void setV1(String v1) {
+        this.v1 = v1;
+    }
+
+    public String getV2() {
+        return v2;
+    }
+
+    public void setV2(String v2) {
+        this.v2 = v2;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/test/java/org/apache/batchee/jackson/util/IOs.java
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/test/java/org/apache/batchee/jackson/util/IOs.java b/extensions/jackson/src/test/java/org/apache/batchee/jackson/util/IOs.java
new file mode 100644
index 0000000..4d38e44
--- /dev/null
+++ b/extensions/jackson/src/test/java/org/apache/batchee/jackson/util/IOs.java
@@ -0,0 +1,62 @@
+/*
+ * 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.jackson.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class IOs {
+    public static void write(final String path, final String content) {
+        final File file = new File(path);
+        if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
+            throw new RuntimeException("Can't create " + path);
+        }
+
+        try {
+            final FileWriter writer = new FileWriter(file);
+            writer.write(content);
+            writer.close();
+        } catch (final IOException e) {
+            // no-op
+        }
+    }
+
+    public static String slurp(final String path) {
+        final StringBuilder builder = new StringBuilder();
+        try {
+            final BufferedReader reader = new BufferedReader(new FileReader(path));
+            String line;
+            do {
+                line = reader.readLine();
+                if (line != null) {
+                    builder.append(line);
+                }
+            } while (line != null);
+            reader.close();
+        } catch (final Exception e) {
+            // no-op
+        }
+        return builder.toString();
+    }
+
+    private IOs() {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-field-writer.xml
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-field-writer.xml b/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-field-writer.xml
new file mode 100644
index 0000000..251bf2c
--- /dev/null
+++ b/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-field-writer.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  See the NOTICE file distributed with this work for additional information
+  regarding copyright ownership. 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.
+-->
+<job id="flat-reader" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
+  <step id="step1">
+    <chunk>
+      <reader ref="org.apache.batchee.jackson.JacksonJSonWriterTest$Reader" />
+      <writer ref="jacksonJSonWriter">
+        <properties>
+          <property name="type" value="org.apache.batchee.jackson.bean.Record"/>
+          <property name="file" value="target/work/jackson-field-output.json"/>
+          <property name="fieldNameGeneratorClass" value="default"/>
+        </properties>
+      </writer>
+    </chunk>
+  </step>
+</job>

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-reader.xml
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-reader.xml b/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-reader.xml
new file mode 100644
index 0000000..2dde206
--- /dev/null
+++ b/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-reader.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  See the NOTICE file distributed with this work for additional information
+  regarding copyright ownership. 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.
+-->
+<job id="flat-reader" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
+  <step id="step1">
+    <chunk>
+      <reader ref="jacksonJSonReader">
+        <properties>
+          <property name="type" value="org.apache.batchee.jackson.bean.Record"/>
+          <property name="file" value="target/work/jackson-input.json"/>
+        </properties>
+      </reader>
+      <writer ref="org.apache.batchee.jackson.JacksonJsonReaderTest$Writer" />
+    </chunk>
+  </step>
+</job>

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-writer.xml
----------------------------------------------------------------------
diff --git a/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-writer.xml b/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-writer.xml
new file mode 100644
index 0000000..104a66b
--- /dev/null
+++ b/extensions/jackson/src/test/resources/META-INF/batch-jobs/jackson-writer.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  See the NOTICE file distributed with this work for additional information
+  regarding copyright ownership. 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.
+-->
+<job id="flat-reader" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
+  <step id="step1">
+    <chunk>
+      <reader ref="org.apache.batchee.jackson.JacksonJSonWriterTest$Reader" />
+      <writer ref="jacksonJSonWriter">
+        <properties>
+          <property name="type" value="org.apache.batchee.jackson.bean.Record"/>
+          <property name="file" value="target/work/jackson-output.json"/>
+        </properties>
+      </writer>
+    </chunk>
+  </step>
+</job>

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/jsefa/pom.xml b/extensions/jsefa/pom.xml
new file mode 100644
index 0000000..c84479f
--- /dev/null
+++ b/extensions/jsefa/pom.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>batchee-extensions</artifactId>
+    <groupId>org.apache.batchee</groupId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>batchee-jsefa</artifactId>
+  <name>BatchEE :: Extensions :: JSefa</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.batchee</groupId>
+      <artifactId>batchee-extras</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jsefa</groupId>
+      <artifactId>jsefa</artifactId>
+      <version>0.9.3.RELEASE</version>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvReader.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvReader.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvReader.java
new file mode 100644
index 0000000..56637d8
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvReader.java
@@ -0,0 +1,80 @@
+/*
+ * 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.jsefa;
+
+import org.jsefa.Deserializer;
+import org.jsefa.csv.CsvIOFactory;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+
+public class JSefaCsvReader extends JSefaReader {
+    @Inject
+    @BatchProperty
+    private String lineFilter;
+
+    @Inject
+    @BatchProperty
+    private String lowLevelConfiguration;
+
+    @Inject
+    @BatchProperty
+    private String lineFilterLimit;
+
+    @Inject
+    @BatchProperty
+    private String specialRecordDelimiter;
+
+    @Inject
+    @BatchProperty
+    private String lineBreak;
+
+    @Inject
+    @BatchProperty
+    private String defaultNoValueString;
+
+    @Inject
+    @BatchProperty
+    private String defaultQuoteMode;
+
+    @Inject
+    @BatchProperty
+    private String fieldDelimiter;
+
+    @Inject
+    @BatchProperty
+    private String quoteCharacter;
+
+    @Inject
+    @BatchProperty
+    private String quoteCharacterEscapeMode;
+
+    @Inject
+    @BatchProperty
+    private String useDelimiterAfterLastField;
+
+    @Override
+    protected Deserializer initDeserializer() throws Exception {
+        return CsvIOFactory.createFactory(
+            JsefaConfigurations.newCsvConfiguration(
+                defaultNoValueString, defaultQuoteMode, fieldDelimiter, lineBreak, quoteCharacter,
+                quoteCharacterEscapeMode, useDelimiterAfterLastField, validationMode, validationProvider,
+                lineFilter, lowLevelConfiguration, lineFilterLimit, objectAccessorProvider,
+                specialRecordDelimiter, simpleTypeProvider, typeMappingRegistry),
+            JsefaConfigurations.createObjectTypes(objectTypes)).createDeserializer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvWriter.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvWriter.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvWriter.java
new file mode 100644
index 0000000..ff9e722
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaCsvWriter.java
@@ -0,0 +1,81 @@
+/*
+ * 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.jsefa;
+
+import org.jsefa.Serializer;
+import org.jsefa.csv.CsvIOFactory;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+
+public class JSefaCsvWriter extends JSefaWriter {
+    @Inject
+    @BatchProperty
+    private String lineFilter;
+
+    @Inject
+    @BatchProperty
+    private String lowLevelConfiguration;
+
+    @Inject
+    @BatchProperty
+    private String lineFilterLimit;
+
+    @Inject
+    @BatchProperty
+    private String specialRecordDelimiter;
+
+    @Inject
+    @BatchProperty
+    private String lineBreak;
+
+    @Inject
+    @BatchProperty
+    private String defaultNoValueString;
+
+    @Inject
+    @BatchProperty
+    private String defaultQuoteMode;
+
+    @Inject
+    @BatchProperty
+    private String fieldDelimiter;
+
+    @Inject
+    @BatchProperty
+    private String quoteCharacter;
+
+    @Inject
+    @BatchProperty
+    private String quoteCharacterEscapeMode;
+
+    @Inject
+    @BatchProperty
+    private String useDelimiterAfterLastField;
+
+    @Override
+    protected Serializer createSerializer() throws Exception {
+        return CsvIOFactory.createFactory(
+            JsefaConfigurations.newCsvConfiguration(
+                defaultNoValueString, defaultQuoteMode, fieldDelimiter, lineBreak, quoteCharacter,
+                quoteCharacterEscapeMode, useDelimiterAfterLastField, validationMode, validationProvider,
+                lineFilter, lowLevelConfiguration, lineFilterLimit, objectAccessorProvider,
+                specialRecordDelimiter, simpleTypeProvider, typeMappingRegistry),
+            JsefaConfigurations.createObjectTypes(objectTypes))
+            .createSerializer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrReader.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrReader.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrReader.java
new file mode 100644
index 0000000..c5fc915
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrReader.java
@@ -0,0 +1,59 @@
+/*
+ * 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.jsefa;
+
+import org.jsefa.Deserializer;
+import org.jsefa.flr.FlrIOFactory;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+
+public class JSefaFlrReader extends JSefaReader {
+    @Inject
+    @BatchProperty
+    private String lineFilter;
+
+    @Inject
+    @BatchProperty
+    private String lowLevelConfiguration;
+
+    @Inject
+    @BatchProperty
+    private String lineFilterLimit;
+
+    @Inject
+    @BatchProperty
+    private String specialRecordDelimiter;
+
+    @Inject
+    @BatchProperty
+    private String lineBreak;
+
+    @Inject
+    @BatchProperty
+    private String defaultPadCharacter;
+
+    @Override
+    protected Deserializer initDeserializer() throws Exception {
+        return FlrIOFactory.createFactory(
+            JsefaConfigurations.newFlrConfiguration(defaultPadCharacter, lineBreak, validationMode, validationProvider,
+                lineFilter, lowLevelConfiguration, lineFilterLimit, objectAccessorProvider, specialRecordDelimiter,
+                simpleTypeProvider, typeMappingRegistry),
+            JsefaConfigurations.createObjectTypes(objectTypes))
+            .createDeserializer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrWriter.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrWriter.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrWriter.java
new file mode 100644
index 0000000..dad7af4
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaFlrWriter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.jsefa;
+
+import org.jsefa.Serializer;
+import org.jsefa.flr.FlrIOFactory;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+
+public class JSefaFlrWriter extends JSefaWriter {
+    @Inject
+    @BatchProperty
+    private String lineFilter;
+
+    @Inject
+    @BatchProperty
+    private String lowLevelConfiguration;
+
+    @Inject
+    @BatchProperty
+    private String lineFilterLimit;
+
+    @Inject
+    @BatchProperty
+    private String specialRecordDelimiter;
+
+    @Inject
+    @BatchProperty
+    private String lineBreak;
+
+    @Inject
+    @BatchProperty
+    private String defaultPadCharacter;
+
+    @Override
+    protected Serializer createSerializer() throws Exception {
+        return FlrIOFactory.createFactory(
+            JsefaConfigurations.newFlrConfiguration(defaultPadCharacter, lineBreak, validationMode, validationProvider,
+                lineFilter, lowLevelConfiguration, lineFilterLimit, objectAccessorProvider, specialRecordDelimiter,
+                simpleTypeProvider, typeMappingRegistry),
+            JsefaConfigurations.createObjectTypes(objectTypes))
+            .createSerializer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaReader.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaReader.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaReader.java
new file mode 100644
index 0000000..6ee69e4
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaReader.java
@@ -0,0 +1,81 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.extras.transaction.CountedReader;
+import org.jsefa.Deserializer;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+import java.io.FileReader;
+import java.io.Serializable;
+
+public abstract class JSefaReader extends CountedReader {
+    @Inject
+    @BatchProperty
+    protected String objectTypes;
+
+    @Inject
+    @BatchProperty
+    protected String validationMode;
+
+    @Inject
+    @BatchProperty
+    protected String objectAccessorProvider;
+
+    @Inject
+    @BatchProperty
+    protected String validationProvider;
+
+    @Inject
+    @BatchProperty
+    protected String simpleTypeProvider;
+
+    @Inject
+    @BatchProperty
+    protected String typeMappingRegistry;
+
+    @Inject
+    @BatchProperty
+    protected String file;
+
+    protected Deserializer deserializer;
+
+    @Override
+    public void open(final Serializable checkpoint) throws Exception {
+        deserializer = initDeserializer();
+        super.open(checkpoint);
+        deserializer.open(new FileReader(file));
+    }
+
+    protected abstract Deserializer initDeserializer() throws Exception;
+
+    @Override
+    protected Object doRead() throws Exception {
+        if (!deserializer.hasNext()) {
+            return null;
+        }
+        return deserializer.next();
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (deserializer != null) {
+            deserializer.close(true);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaWriter.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaWriter.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaWriter.java
new file mode 100644
index 0000000..fff61a1
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaWriter.java
@@ -0,0 +1,99 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.extras.transaction.TransactionalWriter;
+import org.jsefa.Serializer;
+
+import javax.batch.api.BatchProperty;
+import javax.batch.api.chunk.ItemWriter;
+import javax.batch.operations.BatchRuntimeException;
+import javax.inject.Inject;
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+
+public abstract class JSefaWriter implements ItemWriter {
+    @Inject
+    @BatchProperty
+    protected String objectTypes;
+
+    @Inject
+    @BatchProperty
+    protected String validationMode;
+
+    @Inject
+    @BatchProperty
+    protected String objectAccessorProvider;
+
+    @Inject
+    @BatchProperty
+    protected String validationProvider;
+
+    @Inject
+    @BatchProperty
+    protected String simpleTypeProvider;
+
+    @Inject
+    @BatchProperty
+    protected String typeMappingRegistry;
+
+    @Inject
+    @BatchProperty
+    protected String file;
+
+    @Inject
+    @BatchProperty
+    protected String encoding;
+
+    protected Serializer serializer;
+    protected TransactionalWriter transactionalWriter;
+
+    @Override
+    public void open(final Serializable checkpoint) throws Exception {
+        final File f = new File(file);
+        if (!f.getParentFile().exists() && !f.getParentFile().mkdirs()) {
+            throw new BatchRuntimeException(f.getParentFile().getAbsolutePath());
+        }
+
+        serializer = createSerializer();
+        transactionalWriter = new TransactionalWriter(f, encoding, checkpoint);
+        serializer.open(transactionalWriter);
+    }
+
+    protected abstract Serializer createSerializer() throws Exception;
+
+    @Override
+    public void close() throws Exception {
+        if (serializer != null) {
+            serializer.close(true);
+        }
+    }
+
+    @Override
+    public void writeItems(final List<Object> items) throws Exception {
+        for (final Object item : items) {
+            serializer.write(item);
+        }
+        transactionalWriter.flush();
+    }
+
+    @Override
+    public Serializable checkpointInfo() throws Exception {
+        return transactionalWriter.position();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlReader.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlReader.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlReader.java
new file mode 100644
index 0000000..097efc0
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlReader.java
@@ -0,0 +1,60 @@
+/*
+ * 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.jsefa;
+
+import org.jsefa.Deserializer;
+import org.jsefa.xml.XmlIOFactory;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+
+public class JSefaXmlReader extends JSefaReader {
+    @Inject
+    @BatchProperty
+    private String lowLevelConfiguration;
+
+    @Inject
+    @BatchProperty
+    private String lineBreak;
+
+    @Inject
+    @BatchProperty
+    private String dataTypeDefaultNameRegistry;
+
+    @Inject
+    @BatchProperty
+    private String lineIndentation;
+
+    @Inject
+    @BatchProperty
+    private String namespaceManager;
+
+    @Inject
+    @BatchProperty
+    private String dataTypeAttributeName;
+
+    @Override
+    protected Deserializer initDeserializer() throws Exception {
+        return XmlIOFactory.createFactory(
+            JsefaConfigurations.newXmlConfiguration(lineBreak, dataTypeDefaultNameRegistry, lineIndentation,
+                lowLevelConfiguration, namespaceManager, dataTypeAttributeName,
+                validationMode, validationProvider, objectAccessorProvider,
+                simpleTypeProvider, typeMappingRegistry),
+            JsefaConfigurations.createObjectTypes(objectTypes))
+            .createDeserializer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlWriter.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlWriter.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlWriter.java
new file mode 100644
index 0000000..ce8c68c
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JSefaXmlWriter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.jsefa;
+
+import org.jsefa.Serializer;
+import org.jsefa.xml.XmlIOFactory;
+
+import javax.batch.api.BatchProperty;
+import javax.inject.Inject;
+
+public class JSefaXmlWriter extends JSefaWriter {
+    @Inject
+    @BatchProperty
+    private String lowLevelConfiguration;
+
+    @Inject
+    @BatchProperty
+    private String lineBreak;
+
+    @Inject
+    @BatchProperty
+    private String dataTypeDefaultNameRegistry;
+
+    @Inject
+    @BatchProperty
+    private String lineIndentation;
+
+    @Inject
+    @BatchProperty
+    private String namespaceManager;
+
+    @Inject
+    @BatchProperty
+    private String dataTypeAttributeName;
+
+    @Override
+    protected Serializer createSerializer() throws Exception {
+        return XmlIOFactory.createFactory(
+            JsefaConfigurations.newXmlConfiguration(lineBreak, dataTypeDefaultNameRegistry, lineIndentation,
+                lowLevelConfiguration, namespaceManager, dataTypeAttributeName,
+                validationMode, validationProvider, objectAccessorProvider,
+                simpleTypeProvider, typeMappingRegistry),
+            JsefaConfigurations.createObjectTypes(objectTypes))
+            .createSerializer();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JsefaConfigurations.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JsefaConfigurations.java b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JsefaConfigurations.java
new file mode 100644
index 0000000..547f487
--- /dev/null
+++ b/extensions/jsefa/src/main/java/org/apache/batchee/jsefa/JsefaConfigurations.java
@@ -0,0 +1,181 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.extras.lang.Langs;
+import org.jsefa.common.accessor.ObjectAccessorProvider;
+import org.jsefa.common.config.Configuration;
+import org.jsefa.common.config.ValidationMode;
+import org.jsefa.common.converter.provider.SimpleTypeConverterProvider;
+import org.jsefa.common.lowlevel.filter.LineFilter;
+import org.jsefa.common.mapping.EntryPoint;
+import org.jsefa.common.mapping.TypeMappingRegistry;
+import org.jsefa.common.validator.provider.ValidatorProvider;
+import org.jsefa.csv.config.CsvConfiguration;
+import org.jsefa.csv.lowlevel.config.EscapeMode;
+import org.jsefa.csv.lowlevel.config.QuoteMode;
+import org.jsefa.flr.config.FlrConfiguration;
+import org.jsefa.rbf.config.RbfConfiguration;
+import org.jsefa.rbf.lowlevel.config.RbfLowLevelConfiguration;
+import org.jsefa.xml.config.XmlConfiguration;
+import org.jsefa.xml.lowlevel.config.XmlLowLevelConfiguration;
+import org.jsefa.xml.mapping.support.XmlDataTypeDefaultNameRegistry;
+import org.jsefa.xml.namespace.NamespaceManager;
+import org.jsefa.xml.namespace.QName;
+
+public class JsefaConfigurations {
+    public static Class<?>[] createObjectTypes(final String objectTypes) throws ClassNotFoundException {
+        if (objectTypes == null) {
+            throw new NullPointerException("objectTypes shouldn't be null");
+        }
+
+        final String[] types = objectTypes.split(",");
+        final Class<?>[] classes = new Class<?>[types.length];
+        final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        for (int i = 0; i < types.length; i++) {
+            classes[i] = loader.loadClass(types[i]);
+        }
+        return classes;
+    }
+
+    public static <A extends TypeMappingRegistry<?>, B extends EntryPoint<?, ?>> void setConfiguration(final Configuration<A, B> configuration,
+                                                        final String validationMode, final String validationProvider,
+                                                        final String objectAccessorProvider, final String simpleTypeProvider,
+                                                        final String typeMappingRegistry) throws Exception {
+        if (validationMode != null) {
+            configuration.setValidationMode(ValidationMode.valueOf(validationMode));
+        }
+        if (objectAccessorProvider != null) {
+            configuration.setObjectAccessorProvider(ObjectAccessorProvider.class.cast(Thread.currentThread().getContextClassLoader().loadClass(objectAccessorProvider).newInstance()));
+        }
+        if (simpleTypeProvider != null) {
+            configuration.setSimpleTypeConverterProvider(SimpleTypeConverterProvider.class.cast(Thread.currentThread().getContextClassLoader().loadClass(simpleTypeProvider).newInstance()));
+        }
+        if (typeMappingRegistry != null) {
+            configuration.setTypeMappingRegistry((A) Thread.currentThread().getContextClassLoader().loadClass(typeMappingRegistry).newInstance());
+        }
+        if (validationProvider != null) {
+            configuration.setValidatorProvider(ValidatorProvider.class.cast(Thread.currentThread().getContextClassLoader().loadClass(validationProvider).newInstance()));
+        }
+    }
+
+    public static <A extends RbfLowLevelConfiguration> void setRbfConfiguration(final RbfConfiguration<A> configuration,
+                                                                                final String validationMode, final String validationProvider,
+                                                                                final String lowLevelConfiguration, final String objectAccessorProvider,
+                                                                                final String lineFilter, final String lineFilterLimit,
+                                                                                final String specialRecordDelimiter, final String simpleTypeProvider,
+                                                                                final String typeMappingRegistry) throws Exception {
+        setConfiguration(configuration, validationMode, validationProvider, objectAccessorProvider, simpleTypeProvider, typeMappingRegistry);
+        if (lineFilter != null) {
+            configuration.setLineFilter(LineFilter.class.cast(Thread.currentThread().getContextClassLoader().loadClass(lineFilter).newInstance()));
+        }
+        if (lowLevelConfiguration != null) {
+            configuration.setLowLevelConfiguration((A) Thread.currentThread().getContextClassLoader().loadClass(lowLevelConfiguration).newInstance());
+        }
+        if (lineFilterLimit != null) {
+            configuration.setLineFilterLimit(Integer.parseInt(lineFilterLimit));
+        }
+        if (specialRecordDelimiter != null) {
+            configuration.setSpecialRecordDelimiter(specialRecordDelimiter.charAt(0));
+        }
+    }
+
+    public static XmlConfiguration newXmlConfiguration(final String lineBreak, final String dataTypeDefaultNameRegistry, final String lineIndentation,
+                                            final String lowLevelConfiguration, final String namespaceManager, final String dataTypeAttributeName,
+                                            final String validationMode, final String validationProvider,
+                                            final String objectAccessorProvider, final String simpleTypeProvider,
+                                            final String typeMappingRegistry) throws Exception {
+        final XmlConfiguration configuration = new XmlConfiguration();
+        JsefaConfigurations.setConfiguration(configuration, validationMode, validationProvider, objectAccessorProvider, simpleTypeProvider, typeMappingRegistry);
+        if (lineBreak != null) {
+            configuration.setLineBreak(lineBreak);
+        }
+        if (dataTypeDefaultNameRegistry != null) {
+            configuration.setDataTypeDefaultNameRegistry(XmlDataTypeDefaultNameRegistry.class.cast(Thread.currentThread().getContextClassLoader().loadClass(dataTypeDefaultNameRegistry).newInstance()));
+        }
+        if (lineIndentation != null) {
+            configuration.setLineIndentation(lineIndentation);
+        }
+        if (lowLevelConfiguration != null) {
+            configuration.setLowLevelConfiguration(XmlLowLevelConfiguration.class.cast(Thread.currentThread().getContextClassLoader().loadClass(lowLevelConfiguration).newInstance()));
+        }
+        if (namespaceManager != null) {
+            configuration.setNamespaceManager(NamespaceManager.class.cast(Thread.currentThread().getContextClassLoader().loadClass(namespaceManager).newInstance()));
+        }
+        if (dataTypeAttributeName != null) {
+            configuration.setDataTypeAttributeName(QName.create(dataTypeAttributeName.substring(1, dataTypeAttributeName.indexOf("}")), dataTypeAttributeName.substring(dataTypeAttributeName.indexOf("}") + 1))); // allow {xxx}yyy syntax
+        }
+        return configuration;
+    }
+
+    public static CsvConfiguration newCsvConfiguration(final String defaultNoValueString, final String defaultQuoteMode,
+                                                       final String fieldDelimiter, final String lineBreak, final String quoteCharacter,
+                                                       final String quoteCharacterEscapeMode, final String useDelimiterAfterLastField,
+                                                       final String validationMode, final String validationProvider,
+                                                       final String lineFilter, final String lowLevelConfiguration,
+                                                       final String lineFilterLimit, final String objectAccessorProvider,
+                                                       final String specialRecordDelimiter, final String simpleTypeProvider,
+                                                       final String typeMappingRegistry) throws Exception {
+        final CsvConfiguration configuration = new CsvConfiguration();
+        setRbfConfiguration(configuration, validationMode, validationProvider, lowLevelConfiguration, objectAccessorProvider,
+            lineFilter, lineFilterLimit, specialRecordDelimiter, simpleTypeProvider, typeMappingRegistry);
+        if (defaultNoValueString != null) {
+            configuration.setDefaultNoValueString(defaultNoValueString);
+        }
+        if (defaultQuoteMode != null) {
+            configuration.setDefaultQuoteMode(QuoteMode.valueOf(defaultQuoteMode));
+        }
+        if (fieldDelimiter != null) {
+            configuration.setFieldDelimiter(fieldDelimiter.charAt(0));
+        }
+        if (lineBreak != null) {
+            configuration.setLineBreak(Langs.repalceEscapableChars(lineBreak));
+        }
+        if (quoteCharacter != null) {
+            configuration.setQuoteCharacter(quoteCharacter.charAt(0));
+        }
+        if (quoteCharacterEscapeMode != null) {
+            configuration.setQuoteCharacterEscapeMode(EscapeMode.valueOf(quoteCharacterEscapeMode));
+        }
+        if (useDelimiterAfterLastField != null) {
+            configuration.setUseDelimiterAfterLastField(Boolean.parseBoolean(useDelimiterAfterLastField));
+        }
+        return configuration;
+    }
+
+    public static FlrConfiguration newFlrConfiguration(final String defaultPadCharacter, final String lineBreak,
+                                                       final String validationMode, final String validationProvider,
+                                                       final String lineFilter, final String lowLevelConfiguration,
+                                                       final String lineFilterLimit, final String objectAccessorProvider,
+                                                       final String specialRecordDelimiter, final String simpleTypeProvider,
+                                                       final String typeMappingRegistry) throws Exception {
+        final FlrConfiguration configuration = new FlrConfiguration();
+        setRbfConfiguration(configuration, validationMode, validationProvider, lowLevelConfiguration, objectAccessorProvider,
+            lineFilter, lineFilterLimit, specialRecordDelimiter, simpleTypeProvider, typeMappingRegistry);
+        if (lineBreak != null) {
+            configuration.setLineBreak(Langs.repalceEscapableChars(lineBreak));
+        }
+        if (defaultPadCharacter != null) {
+            configuration.setDefaultPadCharacter(defaultPadCharacter.charAt(0));
+        }
+        return configuration;
+    }
+
+    private JsefaConfigurations() {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/main/resources/META-INF/batchee.xml
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/main/resources/META-INF/batchee.xml b/extensions/jsefa/src/main/resources/META-INF/batchee.xml
new file mode 100644
index 0000000..a3aa58e
--- /dev/null
+++ b/extensions/jsefa/src/main/resources/META-INF/batchee.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<batch-artifacts xmlns="http://xmlns.jcp.org/xml/ns/javaee">
+  <ref id="jsefaCsvReader" class="org.apache.batchee.jsefa.JSefaCsvReader" />
+  <ref id="jsefaFlrReader" class="org.apache.batchee.jsefa.JSefaFlrReader" />
+  <ref id="jsefaXmlReader" class="org.apache.batchee.jsefa.JSefaXmlReader" />
+  <ref id="jsefaCsvWriter" class="org.apache.batchee.jsefa.JSefaCsvWriter" />
+  <ref id="jsefaFlrWriter" class="org.apache.batchee.jsefa.JSefaFlrWriter" />
+  <ref id="jsefaXmlWriter" class="org.apache.batchee.jsefa.JSefaXmlWriter" />
+</batch-artifacts>

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvReaderTest.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvReaderTest.java b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvReaderTest.java
new file mode 100644
index 0000000..bed7596
--- /dev/null
+++ b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvReaderTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.jsefa.bean.Record;
+import org.apache.batchee.jsefa.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemProcessor;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.testng.Assert.assertEquals;
+
+public class JSefaCsvReaderTest {
+    @Test
+    public void read() throws Exception {
+        final String path = "target/work/JSefaCsvReader.txt";
+
+        final Properties jobParams = new Properties();
+        jobParams.setProperty("input", path);
+
+        final JobOperator jobOperator = BatchRuntime.getJobOperator();
+        IOs.write(path, "v11;v12\nv21;v22\nv31;v32");
+        Batches.waitForEnd(jobOperator, jobOperator.start("jsefa-csv-reader", jobParams));
+
+        final int size = StoreItems.ITEMS.size();
+        assertEquals(size, 3);
+        for (int i = 1; i <= size; i++) {
+            final Record record = StoreItems.ITEMS.get(i - 1);
+            assertEquals(record.getValue1(), "v" + i + "1");
+            assertEquals(record.getValue2(), "v" + i + "2");
+        }
+    }
+
+    public static class StoreItems implements ItemProcessor {
+        public static final List<Record> ITEMS = new ArrayList<Record>(3);
+
+        @Override
+        public Object processItem(final Object item) throws Exception {
+            ITEMS.add(Record.class.cast(item));
+            return item;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvWriterTest.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvWriterTest.java b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvWriterTest.java
new file mode 100644
index 0000000..f8f4ede
--- /dev/null
+++ b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaCsvWriterTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.jsefa.bean.Record;
+import org.apache.batchee.jsefa.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemReader;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.io.Serializable;
+import java.util.Properties;
+
+import static org.testng.Assert.assertTrue;
+
+public class JSefaCsvWriterTest {
+    @Test
+    public void read() throws Exception {
+        final String path = "target/work/JSefaCsvWriter.txt";
+
+        final Properties jobParams = new Properties();
+        jobParams.setProperty("output", path);
+
+        final JobOperator jobOperator = BatchRuntime.getJobOperator();
+        Batches.waitForEnd(jobOperator, jobOperator.start("jsefa-csv-writer", jobParams));
+        final String output = IOs.slurp(path);
+
+        assertTrue(output.contains("v1_1;v1_2"));
+        assertTrue(output.contains("v2_1;v2_2"));
+    }
+
+    public static class TwoItemsReader implements ItemReader {
+        private int count = 0;
+
+        @Override
+        public void open(final Serializable checkpoint) throws Exception {
+            // no-op
+        }
+
+        @Override
+        public void close() throws Exception {
+            // no-op
+        }
+
+        @Override
+        public Object readItem() throws Exception {
+            if (count++ < 2) {
+                return new Record("v" + count + "_");
+            }
+            return null;
+        }
+
+        @Override
+        public Serializable checkpointInfo() throws Exception {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrReaderTest.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrReaderTest.java b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrReaderTest.java
new file mode 100644
index 0000000..ba37937
--- /dev/null
+++ b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrReaderTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.jsefa.bean.Record;
+import org.apache.batchee.jsefa.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemProcessor;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.testng.Assert.assertEquals;
+
+public class JSefaFlrReaderTest {
+    @Test
+    public void read() throws Exception {
+        final String path = "target/work/JSefaFlrReader.txt";
+
+        final Properties jobParams = new Properties();
+        jobParams.setProperty("input", path);
+
+        final JobOperator jobOperator = BatchRuntime.getJobOperator();
+        IOs.write(path, "v11v12\nv21v22\nv31v32");
+        Batches.waitForEnd(jobOperator, jobOperator.start("jsefa-flr-reader", jobParams));
+
+        final int size = StoreItems.ITEMS.size();
+        assertEquals(size, 3);
+        for (int i = 1; i <= size; i++) {
+            final Record record = StoreItems.ITEMS.get(i - 1);
+            assertEquals(record.getValue1(), "v" + i + "1");
+            assertEquals(record.getValue2(), "v" + i + "2");
+        }
+    }
+
+    public static class StoreItems implements ItemProcessor {
+        public static final List<Record> ITEMS = new ArrayList<Record>(3);
+
+        @Override
+        public Object processItem(final Object item) throws Exception {
+            ITEMS.add(Record.class.cast(item));
+            return item;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrWriterTest.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrWriterTest.java b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrWriterTest.java
new file mode 100644
index 0000000..a0801fe
--- /dev/null
+++ b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaFlrWriterTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.jsefa.bean.Record;
+import org.apache.batchee.jsefa.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemReader;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.io.Serializable;
+import java.util.Properties;
+
+import static org.testng.Assert.assertTrue;
+
+public class JSefaFlrWriterTest {
+    @Test
+    public void read() throws Exception {
+        final String path = "target/work/JSefaFlrWriter.txt";
+
+        final Properties jobParams = new Properties();
+        jobParams.setProperty("output", path);
+
+        final JobOperator jobOperator = BatchRuntime.getJobOperator();
+        Batches.waitForEnd(jobOperator, jobOperator.start("jsefa-flr-writer", jobParams));
+        final String output = IOs.slurp(path);
+
+        assertTrue(output.contains("v11v12"));
+        assertTrue(output.contains("v21v22"));
+    }
+
+    public static class TwoItemsReader implements ItemReader {
+        private int count = 0;
+
+        @Override
+        public void open(final Serializable checkpoint) throws Exception {
+            // no-op
+        }
+
+        @Override
+        public void close() throws Exception {
+            // no-op
+        }
+
+        @Override
+        public Object readItem() throws Exception {
+            if (count++ < 2) {
+                return new Record("v" + count);
+            }
+            return null;
+        }
+
+        @Override
+        public Serializable checkpointInfo() throws Exception {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlReaderTest.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlReaderTest.java b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlReaderTest.java
new file mode 100644
index 0000000..5e97359
--- /dev/null
+++ b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlReaderTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.jsefa.bean.Record;
+import org.apache.batchee.jsefa.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemProcessor;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.testng.Assert.assertEquals;
+
+public class JSefaXmlReaderTest {
+    @Test
+    public void read() throws Exception {
+        final String path = "target/work/JSefaXmlReader.txt";
+
+        final Properties jobParams = new Properties();
+        jobParams.setProperty("input", path);
+
+        final JobOperator jobOperator = BatchRuntime.getJobOperator();
+        IOs.write(path, "<Records><Record><value1>v11</value1><value2>v12</value2></Record><Record><value1>v21</value1><value2>v22</value2></Record><Record><value1>v31</value1><value2>v32</value2></Record></Records>");
+        Batches.waitForEnd(jobOperator, jobOperator.start("jsefa-xml-reader", jobParams));
+
+        final int size = StoreItems.ITEMS.size();
+        assertEquals(size, 3);
+        for (int i = 1; i <= size; i++) {
+            final Record Record = StoreItems.ITEMS.get(i - 1);
+            assertEquals(Record.getValue1(), "v" + i + "1");
+            assertEquals(Record.getValue2(), "v" + i + "2");
+        }
+    }
+
+    public static class StoreItems implements ItemProcessor {
+        public static final List<Record> ITEMS = new ArrayList<Record>(3);
+
+        @Override
+        public Object processItem(final Object item) throws Exception {
+            ITEMS.add(Record.class.cast(item));
+            return item;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlWriterTest.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlWriterTest.java b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlWriterTest.java
new file mode 100644
index 0000000..dd625cb
--- /dev/null
+++ b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/JSefaXmlWriterTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.jsefa;
+
+import org.apache.batchee.jsefa.bean.Record;
+import org.apache.batchee.jsefa.util.IOs;
+import org.apache.batchee.util.Batches;
+import org.testng.annotations.Test;
+
+import javax.batch.api.chunk.ItemReader;
+import javax.batch.operations.JobOperator;
+import javax.batch.runtime.BatchRuntime;
+import java.io.Serializable;
+import java.util.Properties;
+
+import static org.testng.Assert.assertEquals;
+
+public class JSefaXmlWriterTest {
+    @Test
+    public void read() throws Exception {
+        final String path = "target/work/JSefaXmlWriter.txt";
+
+        final Properties jobParams = new Properties();
+        jobParams.setProperty("output", path);
+
+        final JobOperator jobOperator = BatchRuntime.getJobOperator();
+        Batches.waitForEnd(jobOperator, jobOperator.start("jsefa-xml-writer", jobParams));
+        final String output = IOs.slurp(path);
+
+        assertEquals(output.replace(System.getProperty("line.separator"), ""),
+            "<Record>" +
+            "  <value1>v1 1</value1>" +
+            "  <value2>v1 2</value2>" +
+            "</Record>" +
+            "<Record>" +
+            "  <value1>v2 1</value1>" +
+            "  <value2>v2 2</value2>" +
+            "</Record>");
+    }
+
+    public static class TwoItemsReader implements ItemReader {
+        private int count = 0;
+
+        @Override
+        public void open(final Serializable checkpoint) throws Exception {
+            // no-op
+        }
+
+        @Override
+        public void close() throws Exception {
+            // no-op
+        }
+
+        @Override
+        public Object readItem() throws Exception {
+            if (count++ < 2) {
+                return new Record("v" + count + " ");
+            }
+            return null;
+        }
+
+        @Override
+        public Serializable checkpointInfo() throws Exception {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-batchee/blob/efa64877/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/bean/Record.java
----------------------------------------------------------------------
diff --git a/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/bean/Record.java b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/bean/Record.java
new file mode 100644
index 0000000..abe650f
--- /dev/null
+++ b/extensions/jsefa/src/test/java/org/apache/batchee/jsefa/bean/Record.java
@@ -0,0 +1,64 @@
+/*
+ * 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.jsefa.bean;
+
+import org.jsefa.csv.annotation.CsvDataType;
+import org.jsefa.csv.annotation.CsvField;
+import org.jsefa.flr.annotation.FlrDataType;
+import org.jsefa.flr.annotation.FlrField;
+import org.jsefa.xml.annotation.XmlDataType;
+import org.jsefa.xml.annotation.XmlElement;
+
+@CsvDataType
+@FlrDataType
+@XmlDataType(name = "record")
+public class Record {
+    @CsvField(pos = 1)
+    @XmlElement(pos = 1)
+    @FlrField(pos = 1, length = 3)
+    private String value1;
+
+    @CsvField(pos = 2)
+    @XmlElement(pos = 2)
+    @FlrField(pos = 2, length = 3)
+    private String value2;
+
+    public Record(final String s) {
+        value1 = s + "1";
+        value2 = s + "2";
+    }
+
+    public Record() {
+        // no-op
+    }
+
+    public String getValue1() {
+        return value1;
+    }
+
+    public void setValue1(final String value) {
+        this.value1 = value;
+    }
+
+    public String getValue2() {
+        return value2;
+    }
+
+    public void setValue2(final String value) {
+        this.value2 = value;
+    }
+}