From a9c3a130f27293b7e2ff8a5aabac5516b0d8704b Mon Sep 17 00:00:00 2001 From: Bill Soumakis Date: Tue, 28 Aug 2018 01:10:15 +0300 Subject: [PATCH 1/8] (vanilla_csv_writer): First draft implementation without tests --- pom.xml | 6 + writer/pom.xml | 4 + .../com/brogrammers/writer/CsvWriter.java | 120 ++++++++++++++++++ .../java/com/brogrammers/it/CsvWriterIT.java | 82 ++++++++++++ .../com/brogrammers/it/model/TestModel.java | 31 +++++ 5 files changed, 243 insertions(+) create mode 100644 writer/src/main/java/com/brogrammers/writer/CsvWriter.java create mode 100644 writer/src/test/java/com/brogrammers/it/CsvWriterIT.java create mode 100644 writer/src/test/java/com/brogrammers/it/model/TestModel.java diff --git a/pom.xml b/pom.xml index 65104e2..73aecfa 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,12 @@ 2.21.0 test + + + org.reflections + reflections + 0.9.11 + diff --git a/writer/pom.xml b/writer/pom.xml index b5bb48b..be686bf 100644 --- a/writer/pom.xml +++ b/writer/pom.xml @@ -42,6 +42,10 @@ org.mockito mockito-core + + org.reflections + reflections + diff --git a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java new file mode 100644 index 0000000..d7502a8 --- /dev/null +++ b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java @@ -0,0 +1,120 @@ +package com.brogrammers.writer; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import org.reflections.ReflectionUtils; + +public class CsvWriter implements Closeable, Flushable { + + private static final String DEFAULT_FIELD_DELIMITER = ","; + private static final String DEFAULT_LINE_SEPARATOR = System.lineSeparator(); + private boolean newLine = false; + private final Path path; + private final Charset charset; + private final List content; + private final OutputStreamWriter writer; + + public CsvWriter(Path path, Charset charset, List content) { + this.path = Objects.requireNonNull(path); + this.charset = Objects.requireNonNull(charset); + this.content = Objects.requireNonNull(content); + + try { + this.writer = new OutputStreamWriter( + Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING), + charset + ); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void close() { + try { + writer.close(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void flush() { + try { + writer.flush(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + public void write() { + for (int index = 0; index < content.size(); index++) { + newLine = (index != content.size() - 1 || index > 0); + try { + write(content.get(index)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + + private void write(T content) throws IOException { + Set fields = ReflectionUtils.getAllFields(content.getClass()); + + Iterator iterator = fields.iterator(); + + if (newLine) { + writer.write(DEFAULT_LINE_SEPARATOR); + } + boolean isLastField = false; + while (iterator.hasNext()) { + Field field = iterator.next(); + if (!iterator.hasNext()) { + isLastField = true; + } + + writer.write(runGetter(field, content).toString()); + if (!isLastField) { + writer.write(DEFAULT_FIELD_DELIMITER); + } + } + } + + private static Object runGetter(Field field, T content) { + for (Method method : ReflectionUtils.getAllMethods(content.getClass())) { + if (isGet(field, method) || isIs(field, method)) { + if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) { + try { + return method.invoke(content); + } + catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + } + } + throw new IllegalAccessError(); + } + + private static boolean isGet(Field field, Method method) { + return method.getName().startsWith("get") && method.getName().length() == (field.getName().length() + 3); + } + + private static boolean isIs(Field field, Method method) { + return method.getName().startsWith("is") && method.getName().length() == (field.getName().length() + 2); + } +} diff --git a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java new file mode 100644 index 0000000..17cd862 --- /dev/null +++ b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java @@ -0,0 +1,82 @@ +package com.brogrammers.it; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Iterator; +import java.util.Set; + +import org.junit.Test; +import org.reflections.ReflectionUtils; + +import com.brogrammers.it.model.TestModel; +import com.brogrammers.writer.CsvWriter; +import com.google.common.base.Charsets; +import com.google.common.collect.Lists; + +public class CsvWriterIT { + + @Test + public void shouldExtractAllFieldsFromPassedObject() { + TestModel testModel = new TestModel("foo", "bar", 500L, 100); + Set fields = ReflectionUtils.getAllFields(testModel.getClass()); + + assertThat(fields.size(), is(4)); + + //The java reflection mechanism does not guarantee ordering of the fields returned. + Iterator iterator = fields.iterator(); + assertThat(iterator.next().getName(), is("smallerCounter")); + assertThat(iterator.next().getName(), is("counter")); + assertThat(iterator.next().getName(), is("firstName")); + assertThat(iterator.next().getName(), is("lastName")); + + iterator = fields.iterator(); + assertThat(runGetter(iterator.next(), testModel), is(100)); + assertThat(runGetter(iterator.next(), testModel), is(500L)); + assertThat(runGetter(iterator.next(), testModel), is("foo")); + assertThat(runGetter(iterator.next(), testModel), is("bar")); + } + + @Test + public void should_create_given_csv_and_write_data_with_correct_data_types() { + //given + TestModel testModel = new TestModel("foo", "bar", 500L, 100); + CsvWriter csvWriter = new CsvWriter<>(Paths.get("src/test/resources/output.csv"), Charsets.UTF_8, Lists.newArrayList(testModel)); + + //when + csvWriter.write(); + + //then + } + + + private static Object runGetter(Field field, TestModel testModel) { + for (Method method : ReflectionUtils.getAllMethods(testModel.getClass())) { + if (isGet(field, method) || isIs(field, method)) { + if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) { + try { + return method.invoke(testModel); + } + catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + } + } + return null; + } + + private static boolean isGet(Field field, Method method) { + return method.getName().startsWith("get") && method.getName().length() == (field.getName().length() + 3); + } + + private static boolean isIs(Field field, Method method) { + return method.getName().startsWith("is") && method.getName().length() == (field.getName().length() + 2); + } +} diff --git a/writer/src/test/java/com/brogrammers/it/model/TestModel.java b/writer/src/test/java/com/brogrammers/it/model/TestModel.java new file mode 100644 index 0000000..cf8db80 --- /dev/null +++ b/writer/src/test/java/com/brogrammers/it/model/TestModel.java @@ -0,0 +1,31 @@ +package com.brogrammers.it.model; + +public class TestModel { + private final String firstName; + private final String lastName; + private final long counter; + private final int smallerCounter; + + public TestModel(String firstName, String lastName, long counter, int smallerCounter) { + this.firstName = firstName; + this.lastName = lastName; + this.counter = counter; + this.smallerCounter = smallerCounter; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public long getCounter() { + return counter; + } + + public int getSmallerCounter() { + return smallerCounter; + } +} From abd2d8e5e7b87b7e0bad70b37ba83163a8871f66 Mon Sep 17 00:00:00 2001 From: vvsoum Date: Tue, 28 Aug 2018 16:30:23 +0300 Subject: [PATCH 2/8] (vanilla_csv_writer): Refactoring and managed to create and write to csv file --- core/pom.xml | 4 ++ .../brogrammers/utilities/Reflections.java | 37 ++++++++++++ .../com/brogrammers/writer/CsvWriter.java | 57 ++++--------------- .../java/com/brogrammers/it/CsvWriterIT.java | 37 +++--------- writer/src/test/resources/output.csv | 3 + 5 files changed, 63 insertions(+), 75 deletions(-) create mode 100644 core/src/main/java/com/brogrammers/utilities/Reflections.java create mode 100644 writer/src/test/resources/output.csv diff --git a/core/pom.xml b/core/pom.xml index 67c9935..cfa617c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -37,6 +37,10 @@ org.mockito mockito-core + + org.reflections + reflections + diff --git a/core/src/main/java/com/brogrammers/utilities/Reflections.java b/core/src/main/java/com/brogrammers/utilities/Reflections.java new file mode 100644 index 0000000..8b57ae2 --- /dev/null +++ b/core/src/main/java/com/brogrammers/utilities/Reflections.java @@ -0,0 +1,37 @@ +package com.brogrammers.utilities; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.reflections.ReflectionUtils; + +public final class Reflections { + private Reflections() { + + } + + public static Object runGetter(Field field, T content) { + for (Method method : ReflectionUtils.getAllMethods(content.getClass())) { + if (isGet(field, method) || isIs(field, method)) { + if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) { + try { + return method.invoke(content); + } + catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + } + } + throw new IllegalAccessError(); + } + + private static boolean isGet(Field field, Method method) { + return method.getName().startsWith("get") && method.getName().length() == (field.getName().length() + 3); + } + + private static boolean isIs(Field field, Method method) { + return method.getName().startsWith("is") && method.getName().length() == (field.getName().length() + 2); + } +} diff --git a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java index d7502a8..55ee05c 100644 --- a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java +++ b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java @@ -1,12 +1,11 @@ package com.brogrammers.writer; +import static com.brogrammers.utilities.Reflections.runGetter; + +import java.io.BufferedWriter; import java.io.Closeable; -import java.io.Flushable; import java.io.IOException; -import java.io.OutputStreamWriter; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; @@ -18,15 +17,14 @@ import org.reflections.ReflectionUtils; -public class CsvWriter implements Closeable, Flushable { +public class CsvWriter implements Closeable { private static final String DEFAULT_FIELD_DELIMITER = ","; - private static final String DEFAULT_LINE_SEPARATOR = System.lineSeparator(); private boolean newLine = false; + private BufferedWriter writer; private final Path path; private final Charset charset; private final List content; - private final OutputStreamWriter writer; public CsvWriter(Path path, Charset charset, List content) { this.path = Objects.requireNonNull(path); @@ -34,10 +32,7 @@ public CsvWriter(Path path, Charset charset, List content) { this.content = Objects.requireNonNull(content); try { - this.writer = new OutputStreamWriter( - Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING), - charset - ); + this.writer = Files.newBufferedWriter(path, charset, StandardOpenOption.CREATE, StandardOpenOption.APPEND); } catch (IOException e) { throw new IllegalStateException(e); } @@ -52,13 +47,8 @@ public void close() { } } - @Override - public void flush() { - try { - writer.flush(); - } catch (IOException e) { - throw new IllegalStateException(e); - } + public void setWriter(BufferedWriter writer) { + this.writer = writer; } public void write() { @@ -66,6 +56,7 @@ public void write() { newLine = (index != content.size() - 1 || index > 0); try { write(content.get(index)); + writer.flush(); } catch (IOException e) { throw new IllegalStateException(e); } @@ -78,7 +69,7 @@ private void write(T content) throws IOException { Iterator iterator = fields.iterator(); if (newLine) { - writer.write(DEFAULT_LINE_SEPARATOR); + writer.newLine(); } boolean isLastField = false; while (iterator.hasNext()) { @@ -87,34 +78,10 @@ private void write(T content) throws IOException { isLastField = true; } - writer.write(runGetter(field, content).toString()); + writer.append(runGetter(field, content).toString()); if (!isLastField) { - writer.write(DEFAULT_FIELD_DELIMITER); - } - } - } - - private static Object runGetter(Field field, T content) { - for (Method method : ReflectionUtils.getAllMethods(content.getClass())) { - if (isGet(field, method) || isIs(field, method)) { - if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) { - try { - return method.invoke(content); - } - catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException(e); - } - } + writer.append(DEFAULT_FIELD_DELIMITER); } } - throw new IllegalAccessError(); - } - - private static boolean isGet(Field field, Method method) { - return method.getName().startsWith("get") && method.getName().length() == (field.getName().length() + 3); - } - - private static boolean isIs(Field field, Method method) { - return method.getName().startsWith("is") && method.getName().length() == (field.getName().length() + 2); } } diff --git a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java index 17cd862..c652e11 100644 --- a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java +++ b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java @@ -1,13 +1,11 @@ package com.brogrammers.it; +import static com.brogrammers.utilities.Reflections.runGetter; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.charset.Charset; -import java.nio.file.Files; import java.nio.file.Paths; import java.util.Iterator; import java.util.Set; @@ -46,37 +44,16 @@ public void shouldExtractAllFieldsFromPassedObject() { @Test public void should_create_given_csv_and_write_data_with_correct_data_types() { //given - TestModel testModel = new TestModel("foo", "bar", 500L, 100); - CsvWriter csvWriter = new CsvWriter<>(Paths.get("src/test/resources/output.csv"), Charsets.UTF_8, Lists.newArrayList(testModel)); + TestModel testModel1 = new TestModel("foo", "bar", 500L, 100); + TestModel testModel2 = new TestModel("baz", "boom", 3000L, 500); + CsvWriter csvWriter = new CsvWriter<>(Paths.get("src/test/resources/output.csv"), Charsets.UTF_8, Lists.newArrayList(testModel1, testModel2)); //when csvWriter.write(); //then - } - - - private static Object runGetter(Field field, TestModel testModel) { - for (Method method : ReflectionUtils.getAllMethods(testModel.getClass())) { - if (isGet(field, method) || isIs(field, method)) { - if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) { - try { - return method.invoke(testModel); - } - catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - } - } - } - return null; - } - - private static boolean isGet(Field field, Method method) { - return method.getName().startsWith("get") && method.getName().length() == (field.getName().length() + 3); - } - private static boolean isIs(Field field, Method method) { - return method.getName().startsWith("is") && method.getName().length() == (field.getName().length() + 2); + //For now since the reader is not yet ready I don't have anything automated to assert that the correct contents have been written. + assertEquals(1L, 1L); } } diff --git a/writer/src/test/resources/output.csv b/writer/src/test/resources/output.csv new file mode 100644 index 0000000..2ce39db --- /dev/null +++ b/writer/src/test/resources/output.csv @@ -0,0 +1,3 @@ + +100,500,foo,bar +500,3000,baz,boom \ No newline at end of file From 6793e5b07b49868d3a04b7c573418ee1f8e779a8 Mon Sep 17 00:00:00 2001 From: Bill Soumakis Date: Wed, 29 Aug 2018 22:30:48 +0300 Subject: [PATCH 3/8] (vanilla_csv_writer): Fixed bug where there was a blank line at the start of the file --- writer/src/main/java/com/brogrammers/writer/CsvWriter.java | 2 +- writer/src/test/java/com/brogrammers/it/CsvWriterIT.java | 1 + writer/src/test/resources/output.csv | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java index 55ee05c..adf2f10 100644 --- a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java +++ b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java @@ -53,7 +53,7 @@ public void setWriter(BufferedWriter writer) { public void write() { for (int index = 0; index < content.size(); index++) { - newLine = (index != content.size() - 1 || index > 0); + newLine = index > 0; try { write(content.get(index)); writer.flush(); diff --git a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java index c652e11..3bf2989 100644 --- a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java +++ b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java @@ -46,6 +46,7 @@ public void should_create_given_csv_and_write_data_with_correct_data_types() { //given TestModel testModel1 = new TestModel("foo", "bar", 500L, 100); TestModel testModel2 = new TestModel("baz", "boom", 3000L, 500); + CsvWriter csvWriter = new CsvWriter<>(Paths.get("src/test/resources/output.csv"), Charsets.UTF_8, Lists.newArrayList(testModel1, testModel2)); //when diff --git a/writer/src/test/resources/output.csv b/writer/src/test/resources/output.csv index 2ce39db..c231621 100644 --- a/writer/src/test/resources/output.csv +++ b/writer/src/test/resources/output.csv @@ -1,3 +1,2 @@ - 100,500,foo,bar 500,3000,baz,boom \ No newline at end of file From 7cdee64926ac9144c2d723d3e3a4c0401b866090 Mon Sep 17 00:00:00 2001 From: Bill Soumakis Date: Wed, 29 Aug 2018 22:44:18 +0300 Subject: [PATCH 4/8] (vanilla_csv_writer): Refactoring --- .../com/brogrammers/writer/CsvWriter.java | 30 +++++-------------- .../java/com/brogrammers/it/CsvWriterIT.java | 18 +++++++++-- .../com/brogrammers/writer/CsvWriterTest.java | 4 +++ writer/src/test/resources/output.csv | 2 -- 4 files changed, 27 insertions(+), 27 deletions(-) create mode 100644 writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java delete mode 100644 writer/src/test/resources/output.csv diff --git a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java index adf2f10..7bb9d24 100644 --- a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java +++ b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java @@ -2,17 +2,12 @@ import static com.brogrammers.utilities.Reflections.runGetter; -import java.io.BufferedWriter; import java.io.Closeable; import java.io.IOException; +import java.io.Writer; import java.lang.reflect.Field; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.util.Iterator; import java.util.List; -import java.util.Objects; import java.util.Set; import org.reflections.ReflectionUtils; @@ -21,21 +16,10 @@ public class CsvWriter implements Closeable { private static final String DEFAULT_FIELD_DELIMITER = ","; private boolean newLine = false; - private BufferedWriter writer; - private final Path path; - private final Charset charset; - private final List content; + private Writer writer; - public CsvWriter(Path path, Charset charset, List content) { - this.path = Objects.requireNonNull(path); - this.charset = Objects.requireNonNull(charset); - this.content = Objects.requireNonNull(content); - - try { - this.writer = Files.newBufferedWriter(path, charset, StandardOpenOption.CREATE, StandardOpenOption.APPEND); - } catch (IOException e) { - throw new IllegalStateException(e); - } + public static CsvWriter create(Writer writer) { + return new CsvWriter<>(writer); } @Override @@ -47,11 +31,11 @@ public void close() { } } - public void setWriter(BufferedWriter writer) { + private CsvWriter(Writer writer) { this.writer = writer; } - public void write() { + public void write(List content) { for (int index = 0; index < content.size(); index++) { newLine = index > 0; try { @@ -69,7 +53,7 @@ private void write(T content) throws IOException { Iterator iterator = fields.iterator(); if (newLine) { - writer.newLine(); + writer.append(System.lineSeparator()); } boolean isLastField = false; while (iterator.hasNext()) { diff --git a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java index 3bf2989..1f627d4 100644 --- a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java +++ b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java @@ -5,7 +5,11 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Writer; import java.lang.reflect.Field; +import java.nio.file.Files; import java.nio.file.Paths; import java.util.Iterator; import java.util.Set; @@ -47,14 +51,24 @@ public void should_create_given_csv_and_write_data_with_correct_data_types() { TestModel testModel1 = new TestModel("foo", "bar", 500L, 100); TestModel testModel2 = new TestModel("baz", "boom", 3000L, 500); - CsvWriter csvWriter = new CsvWriter<>(Paths.get("src/test/resources/output.csv"), Charsets.UTF_8, Lists.newArrayList(testModel1, testModel2)); + Writer writer = createWriter(); + + CsvWriter csvWriter = CsvWriter.create(writer); //when - csvWriter.write(); + csvWriter.write(Lists.newArrayList(testModel1, testModel2)); //then //For now since the reader is not yet ready I don't have anything automated to assert that the correct contents have been written. assertEquals(1L, 1L); } + + private BufferedWriter createWriter() { + try { + return Files.newBufferedWriter(Paths.get("src/test/resources/output.csv"), Charsets.UTF_8); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } } diff --git a/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java b/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java new file mode 100644 index 0000000..81f652e --- /dev/null +++ b/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java @@ -0,0 +1,4 @@ +package com.brogrammers.writer; + +public class CsvWriterTest { +} diff --git a/writer/src/test/resources/output.csv b/writer/src/test/resources/output.csv deleted file mode 100644 index c231621..0000000 --- a/writer/src/test/resources/output.csv +++ /dev/null @@ -1,2 +0,0 @@ -100,500,foo,bar -500,3000,baz,boom \ No newline at end of file From 7ea19f8f94efd305cd8f9d4ad73ef45525c7aa27 Mon Sep 17 00:00:00 2001 From: Bill Soumakis Date: Thu, 30 Aug 2018 00:34:42 +0300 Subject: [PATCH 5/8] (vanilla_csv_writer): Updated README.md and completed unit and integration tests --- README.md | 6 +- .../com/brogrammers/writer/CsvWriter.java | 14 ++- .../java/com/brogrammers/it/CsvWriterIT.java | 30 +------ .../brogrammers/{it => }/model/TestModel.java | 2 +- .../com/brogrammers/writer/CsvWriterTest.java | 86 +++++++++++++++++++ writer/src/test/resources/output.csv | 2 + 6 files changed, 105 insertions(+), 35 deletions(-) rename writer/src/test/java/com/brogrammers/{it => }/model/TestModel.java (95%) create mode 100644 writer/src/test/resources/output.csv diff --git a/README.md b/README.md index 05d35ad..06c144f 100644 --- a/README.md +++ b/README.md @@ -34,4 +34,8 @@ - mvn verify **Package Application:** -- mvn clean package \ No newline at end of file +- mvn clean package + +**Debug unit tests with maven** +- mvn -Dmaven.surefire.debug test +- Attach a debugger listening to port 5005 \ No newline at end of file diff --git a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java index 7bb9d24..bce839e 100644 --- a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java +++ b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java @@ -8,6 +8,7 @@ import java.lang.reflect.Field; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Set; import org.reflections.ReflectionUtils; @@ -31,10 +32,6 @@ public void close() { } } - private CsvWriter(Writer writer) { - this.writer = writer; - } - public void write(List content) { for (int index = 0; index < content.size(); index++) { newLine = index > 0; @@ -47,6 +44,10 @@ public void write(List content) { } } + private CsvWriter(Writer writer) { + this.writer = Objects.requireNonNull(writer); + } + private void write(T content) throws IOException { Set fields = ReflectionUtils.getAllFields(content.getClass()); @@ -58,6 +59,11 @@ private void write(T content) throws IOException { boolean isLastField = false; while (iterator.hasNext()) { Field field = iterator.next(); + + //We need to ignore synthetic fields possibly introduced by external tools in order not to output those too + if (field.isSynthetic()) { + continue; + } if (!iterator.hasNext()) { isLastField = true; } diff --git a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java index 1f627d4..24b5f1b 100644 --- a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java +++ b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java @@ -1,50 +1,22 @@ package com.brogrammers.it; -import static com.brogrammers.utilities.Reflections.runGetter; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; -import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.Iterator; -import java.util.Set; import org.junit.Test; -import org.reflections.ReflectionUtils; -import com.brogrammers.it.model.TestModel; +import com.brogrammers.model.TestModel; import com.brogrammers.writer.CsvWriter; import com.google.common.base.Charsets; import com.google.common.collect.Lists; public class CsvWriterIT { - @Test - public void shouldExtractAllFieldsFromPassedObject() { - TestModel testModel = new TestModel("foo", "bar", 500L, 100); - Set fields = ReflectionUtils.getAllFields(testModel.getClass()); - - assertThat(fields.size(), is(4)); - - //The java reflection mechanism does not guarantee ordering of the fields returned. - Iterator iterator = fields.iterator(); - assertThat(iterator.next().getName(), is("smallerCounter")); - assertThat(iterator.next().getName(), is("counter")); - assertThat(iterator.next().getName(), is("firstName")); - assertThat(iterator.next().getName(), is("lastName")); - - iterator = fields.iterator(); - assertThat(runGetter(iterator.next(), testModel), is(100)); - assertThat(runGetter(iterator.next(), testModel), is(500L)); - assertThat(runGetter(iterator.next(), testModel), is("foo")); - assertThat(runGetter(iterator.next(), testModel), is("bar")); - } - @Test public void should_create_given_csv_and_write_data_with_correct_data_types() { //given diff --git a/writer/src/test/java/com/brogrammers/it/model/TestModel.java b/writer/src/test/java/com/brogrammers/model/TestModel.java similarity index 95% rename from writer/src/test/java/com/brogrammers/it/model/TestModel.java rename to writer/src/test/java/com/brogrammers/model/TestModel.java index cf8db80..1b95083 100644 --- a/writer/src/test/java/com/brogrammers/it/model/TestModel.java +++ b/writer/src/test/java/com/brogrammers/model/TestModel.java @@ -1,4 +1,4 @@ -package com.brogrammers.it.model; +package com.brogrammers.model; public class TestModel { private final String firstName; diff --git a/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java b/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java index 81f652e..f0e2dfa 100644 --- a/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java +++ b/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java @@ -1,4 +1,90 @@ package com.brogrammers.writer; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import com.brogrammers.model.TestModel; +import com.google.common.collect.Lists; + public class CsvWriterTest { + + public Writer writter; + + @Before + public void setup() { + writter = mock(Writer.class); + } + + + @Test + public void should_delegate_writes_to_passed_writer() throws IOException { + //given + List content = Lists.newArrayList( + new TestModel("foo", "bar", 100L, 50), + new TestModel("baz", "foob", 5000L, 300) + ); + + CsvWriter csvWriter = CsvWriter.create(writter); + + //when + csvWriter.write(content); + + //then + + //The number of times the append is called is the sum of all the fields written and the line separators and field separators. + verify(writter, times(15)).append(any(String.class)); + verify(writter, times(1)).append(System.lineSeparator()); + verify(writter, times(2)).flush(); + } + + @Test + public void should_close_the_given_writer() throws IOException { + //given + CsvWriter csvWriter = CsvWriter.create(writter); + + //when + csvWriter.close(); + + //then + verify(writter, times(1)).close(); + } + + @Test(expected = IllegalStateException.class) + public void should_throw_IllegalStateException_when_IOException_is_thrown_in_close() throws IOException { + //given + CsvWriter csvWriter = CsvWriter.create(writter); + doThrow(new IOException()).when(writter).close(); + + //when + csvWriter.close(); + } + + @Test(expected = IllegalStateException.class) + public void should_throw_IllegalStateException_when_IOException_is_thrown_in_append() throws IOException { + //given + List content = Lists.newArrayList( + new TestModel("foo", "bar", 100L, 50), + new TestModel("baz", "foob", 5000L, 300) + ); + CsvWriter csvWriter = CsvWriter.create(writter); + doThrow(new IOException()).when(writter).append(any(String.class)); + + //when + csvWriter.write(content); + } + + @Test(expected = NullPointerException.class) + public void should_throw_NullPointerException_when_given_writer_is_null() { + CsvWriter.create(null); + } } diff --git a/writer/src/test/resources/output.csv b/writer/src/test/resources/output.csv new file mode 100644 index 0000000..c231621 --- /dev/null +++ b/writer/src/test/resources/output.csv @@ -0,0 +1,2 @@ +100,500,foo,bar +500,3000,baz,boom \ No newline at end of file From e54fca99de6443a474dffb3e560d7b13e895d0c6 Mon Sep 17 00:00:00 2001 From: Bill Soumakis Date: Thu, 30 Aug 2018 00:41:44 +0300 Subject: [PATCH 6/8] (vanilla_csv_writer): Added javadoc --- .../main/java/com/brogrammers/utilities/Reflections.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/java/com/brogrammers/utilities/Reflections.java b/core/src/main/java/com/brogrammers/utilities/Reflections.java index 8b57ae2..f389a19 100644 --- a/core/src/main/java/com/brogrammers/utilities/Reflections.java +++ b/core/src/main/java/com/brogrammers/utilities/Reflections.java @@ -11,6 +11,15 @@ private Reflections() { } + /** + * Searches and invokes through reflection the correct getter method + * for the provided {@link Field} object. + * @param field The field to search for the appropriate public getter + * @param content The object on which we use reflection + * @param + * @return The type of the public getter of the field + * @throws IllegalAccessError if either no appropriate public getter is found or no method at all. + */ public static Object runGetter(Field field, T content) { for (Method method : ReflectionUtils.getAllMethods(content.getClass())) { if (isGet(field, method) || isIs(field, method)) { From c397fe0aa65f2abca180d08ee1d0aaf4e2098a72 Mon Sep 17 00:00:00 2001 From: vvsoum Date: Thu, 30 Aug 2018 17:22:58 +0300 Subject: [PATCH 7/8] (vanilla_csv_writer): Refactoring --- .../main/java/com/brogrammers/writer/CsvWriter.java | 3 ++- .../src/test/java/com/brogrammers/it/CsvWriterIT.java | 2 +- .../java/com/brogrammers/writer/CsvWriterTest.java | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java index bce839e..b3d2135 100644 --- a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java +++ b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java @@ -19,7 +19,7 @@ public class CsvWriter implements Closeable { private boolean newLine = false; private Writer writer; - public static CsvWriter create(Writer writer) { + public static CsvWriter newInstance(Writer writer) { return new CsvWriter<>(writer); } @@ -34,6 +34,7 @@ public void close() { public void write(List content) { for (int index = 0; index < content.size(); index++) { + //Only add a new line when there is more than one element in the contents to write newLine = index > 0; try { write(content.get(index)); diff --git a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java index 24b5f1b..694e3b8 100644 --- a/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java +++ b/writer/src/test/java/com/brogrammers/it/CsvWriterIT.java @@ -25,7 +25,7 @@ public void should_create_given_csv_and_write_data_with_correct_data_types() { Writer writer = createWriter(); - CsvWriter csvWriter = CsvWriter.create(writer); + CsvWriter csvWriter = CsvWriter.newInstance(writer); //when csvWriter.write(Lists.newArrayList(testModel1, testModel2)); diff --git a/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java b/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java index f0e2dfa..f3f9130 100644 --- a/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java +++ b/writer/src/test/java/com/brogrammers/writer/CsvWriterTest.java @@ -34,7 +34,7 @@ public void should_delegate_writes_to_passed_writer() throws IOException { new TestModel("baz", "foob", 5000L, 300) ); - CsvWriter csvWriter = CsvWriter.create(writter); + CsvWriter csvWriter = CsvWriter.newInstance(writter); //when csvWriter.write(content); @@ -50,7 +50,7 @@ public void should_delegate_writes_to_passed_writer() throws IOException { @Test public void should_close_the_given_writer() throws IOException { //given - CsvWriter csvWriter = CsvWriter.create(writter); + CsvWriter csvWriter = CsvWriter.newInstance(writter); //when csvWriter.close(); @@ -62,7 +62,7 @@ public void should_close_the_given_writer() throws IOException { @Test(expected = IllegalStateException.class) public void should_throw_IllegalStateException_when_IOException_is_thrown_in_close() throws IOException { //given - CsvWriter csvWriter = CsvWriter.create(writter); + CsvWriter csvWriter = CsvWriter.newInstance(writter); doThrow(new IOException()).when(writter).close(); //when @@ -76,7 +76,7 @@ public void should_throw_IllegalStateException_when_IOException_is_thrown_in_app new TestModel("foo", "bar", 100L, 50), new TestModel("baz", "foob", 5000L, 300) ); - CsvWriter csvWriter = CsvWriter.create(writter); + CsvWriter csvWriter = CsvWriter.newInstance(writter); doThrow(new IOException()).when(writter).append(any(String.class)); //when @@ -85,6 +85,6 @@ public void should_throw_IllegalStateException_when_IOException_is_thrown_in_app @Test(expected = NullPointerException.class) public void should_throw_NullPointerException_when_given_writer_is_null() { - CsvWriter.create(null); + CsvWriter.newInstance(null); } } From e1079f4fed7dcac58b18f6118852335244a75f87 Mon Sep 17 00:00:00 2001 From: vvsoum Date: Thu, 30 Aug 2018 17:27:27 +0300 Subject: [PATCH 8/8] (vanilla_csv_writer): Replaced Closeable with AutoCloseable interface for CsvWriter --- writer/src/main/java/com/brogrammers/writer/CsvWriter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java index b3d2135..3cfe915 100644 --- a/writer/src/main/java/com/brogrammers/writer/CsvWriter.java +++ b/writer/src/main/java/com/brogrammers/writer/CsvWriter.java @@ -2,7 +2,6 @@ import static com.brogrammers.utilities.Reflections.runGetter; -import java.io.Closeable; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Field; @@ -13,7 +12,7 @@ import org.reflections.ReflectionUtils; -public class CsvWriter implements Closeable { +public class CsvWriter implements AutoCloseable { private static final String DEFAULT_FIELD_DELIMITER = ","; private boolean newLine = false;