Skip to content
Snippets Groups Projects
Commit 9d73aa07 authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

Added Javadoc to public methods for student benefit (and good practice)

parent 84d7e5ca
Branches
Tags
No related merge requests found
......@@ -13,6 +13,13 @@ public abstract class AbstractFormattedFile implements FormattedFile {
fields = new LinkedHashSet<>();
}
/**
* Provides a collection of unique field names. If the file has not been read from nor written to, there are no
* guarantees that the returned {@link java.util.Set} contains an accurate collection of field names. Otherwise, the
* {@link java.util.Set} will contain the fields names that are current as of the last file access.
*
* @return a {@link java.util.Set} of the file's field names
*/
public Set<String> getFields() {
return Collections.unmodifiableSet(fields);
}
......
......@@ -13,12 +13,20 @@ import java.io.*;
import java.net.URL;
import java.util.*;
@SuppressWarnings("unused")
public class CsvFile extends AbstractFormattedFile implements FormattedFile {
CsvFile(String filename) {
super("csv/" + filename + ".csv");
}
/**
* Provides the contents of the file as a mapping from the CSV header entries to the values for those header
* entries. Each {@link java.util.Map} will represent a CSV row. The {@link java.util.Map}s will be returned as a
* {@link java.util.Collection}; no guarantees are made about the order they will be accessed when iterating over
* the {@link java.util.Collection}.
*
* @return a {@link java.util.Collection} of {@link java.util.Map}s that relate CSV header entries to values for
* each CSV row
*/
@Override
public Collection<Map<String, String>> readFile() {
List<Map<String, String>> csvList = null;
......@@ -36,23 +44,13 @@ public class CsvFile extends AbstractFormattedFile implements FormattedFile {
return csvList;
}
Collection<Map<String, String>> parseCSV(Reader reader, Collection<Map<String, String>> destination) {
Map<String, String> line;
try {
CSVReaderHeaderAware csvReader = new CSVReaderHeaderAwareBuilder(reader).build();
while ((line = csvReader.readMap()) != null) {
destination.add(line);
}
} catch (NullPointerException ignored) {
// CSVReaderHeaderAwareBuilder.build() throws NullPointerException if reader is empty
} catch (IOException ioException) {
System.err.println("Error reading CSV file. " + ioException);
} catch (CsvValidationException csvValidationException) {
System.err.println("Could not validate a line in CSV file. " + csvValidationException);
}
return destination;
}
/**
* Overwrites the file's contents with the data passed to this method, in the file's format.
*
* @param data a {@link java.util.Collection} of {@link java.util.Map}s that relate fields to values; see
* {@link #readFile()} for a description of this data structure
* @return {@code true} if the file was successfully written to; {@code false} otherwise
*/
@Override
public boolean writeFile(Collection<Map<String, String>> data) {
boolean wroteFile = true;
......@@ -61,9 +59,9 @@ public class CsvFile extends AbstractFormattedFile implements FormattedFile {
if (resource == null) {
try {
String s = Objects.requireNonNull(classLoader.getResource(("csv/"))).getFile();
File f = new File(s, filename);
File file = new File(s, filename);
//noinspection ResultOfMethodCallIgnored
f.createNewFile();
file.createNewFile();
} catch (IOException ioException) {
System.err.println("Error creating " + filename + ". " + ioException);
}
......@@ -74,7 +72,8 @@ public class CsvFile extends AbstractFormattedFile implements FormattedFile {
try (FileWriter fileWriter = new FileWriter(file)) {
placeCSVonWriter(data, fileWriter);
} catch (FileNotFoundException fileNotFoundException) {
System.err.println("Could not open " + filename + "; probably due to a bad pathname. " + fileNotFoundException);
System.err.println("Could not open " + filename + "; probably due to a bad pathname. " +
fileNotFoundException);
wroteFile = false;
} catch (IOException ioException) {
System.err.println("Error opening " + filename + ". " + ioException);
......@@ -87,6 +86,77 @@ public class CsvFile extends AbstractFormattedFile implements FormattedFile {
return wroteFile;
}
/**
* Converts a {@link java.util.List} or {@link java.util.Set} (or any other {@link java.util.Collection}) into a
* delimited {@link java.lang.String} suitable for storage as an entry in a CSV file. The
* {@link java.util.Collection}'s elements will be stored in the string, separated by the specified delimiter.
*
* @param collection the data to be placed in a delimited string
* @param delimiter the delimiter that will separate the elements in the string
* @return a {@link java.lang.String} representing the {@link java.util.Collection}
*/
public static String createDelimitedCollection(Collection<String> collection, String delimiter) {
if (delimiter.equals("\"")) {
throw new IllegalArgumentException("The double-quote character \" cannot be a delimiter.");
}
StringBuilder delimitedCollection = new StringBuilder();
int tokensRemaining = collection.size();
for (String datum : collection) {
if (datum.contains(delimiter)) {
delimitedCollection.append("\"").append(datum).append("\"");
} else {
delimitedCollection.append(datum);
}
if (--tokensRemaining > 0) {
delimitedCollection.append(delimiter);
}
}
return delimitedCollection.toString();
}
/**
* Converts a delimited "list" from a {@link java.lang.String} representation to a {@link java.util.List}. For
* example, {@code createFreeList("foo bar", " ")} returns {@code ["foo", "bar"]}.
*
* @param delimitedCollection the delimited {@link java.lang.String} to be converted into a {@link java.util.List}
* @param delimiter the delimiter that separates elements of the "list"
* @return a {@link java.util.List} of {@link java.lang.String}s corresponding to the delimited "list"
*/
@SuppressWarnings("unused")
public static List<String> createFreeList(String delimitedCollection, String delimiter) {
return (List<String>) createFreeCollection(delimitedCollection, delimiter, new LinkedList<>());
}
/**
* Converts a delimited "set" from a {@link java.lang.String} representation to a {@link java.util.Set}. For
* example, {@code createFreeList("foo bar", " ")} returns {@code {"foo", "bar"}}.
*
* @param delimitedCollection the delimited {@link java.lang.String} to be converted into a {@link java.util.Set}
* @param delimiter the delimiter that separates elements of the "set"
* @return a {@link java.util.List} of Strings corresponding to the delimited "set"
*/
@SuppressWarnings("unused")
public static Set<String> createFreeSet(String delimitedCollection, String delimiter) {
return (Set<String>) createFreeCollection(delimitedCollection, delimiter, new HashSet<>());
}
Collection<Map<String, String>> parseCSV(Reader reader, Collection<Map<String, String>> destination) {
Map<String, String> line;
try {
CSVReaderHeaderAware csvReader = new CSVReaderHeaderAwareBuilder(reader).build();
while ((line = csvReader.readMap()) != null) {
destination.add(line);
}
} catch (NullPointerException ignored) {
// CSVReaderHeaderAwareBuilder.build() throws NullPointerException if reader is empty
} catch (IOException ioException) {
System.err.println("Error reading CSV file. " + ioException);
} catch (CsvValidationException csvValidationException) {
System.err.println("Could not validate a line in CSV file. " + csvValidationException);
}
return destination;
}
void placeCSVonWriter(Collection<Map<String, String>> data, Writer writer) {
CSVWriter csvWriter = new CSVWriter(writer);
List<String[]> allLines = new LinkedList<>();
......@@ -115,33 +185,6 @@ public class CsvFile extends AbstractFormattedFile implements FormattedFile {
return fieldArray;
}
public static String createDelimitedCollection(Collection<String> collection, String delimiter) {
if (delimiter.equals("\"")) {
throw new IllegalArgumentException("The double-quote character \" cannot be a delimiter.");
}
StringBuilder delimitedCollection = new StringBuilder();
int tokensRemaining = collection.size();
for (String datum : collection) {
if (datum.contains(delimiter)) {
delimitedCollection.append("\"").append(datum).append("\"");
} else {
delimitedCollection.append(datum);
}
if (--tokensRemaining > 0) {
delimitedCollection.append(delimiter);
}
}
return delimitedCollection.toString();
}
public static List<String> createFreeList(String delimitedCollection, String delimiter) {
return (List<String>) createFreeCollection(delimitedCollection, delimiter, new LinkedList<>());
}
public static Set<String> createFreeSet(String delimitedCollection, String delimiter) {
return (Set<String>) createFreeCollection(delimitedCollection, delimiter, new HashSet<>());
}
static Collection<String> createFreeCollection(String delimitedCollection, String delimiter,
Collection<String> collection) {
// NOTE: if there are 2n+1 quotes, where n>0, then the delimitedCollection is ambiguous
......
......@@ -4,10 +4,39 @@ import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Provides access to the contents of a data file in a well-defined format, such as CSV or JSON.
*/
@SuppressWarnings("unused")
public interface FormattedFile {
// TODO: change from Map<String,String> to Map<String,Object>, where Object is constrained to String, Long, Boolean, or List<String>
// TODO: change from Map<String,String> to Map<String,Object>, where Object is constrained to String, Long,
// Boolean, or List<String>
/**
* Provides the contents of the file as a mapping from the fields (such as CSV headers) to the values for those
* fields. Each {@link java.util.Map} will represent a single entity (such as a CSV row). The
* {@link java.util.Map}s will be returned as a {@link java.util.Collection}; no guarantees are made about the
* order they will be accessed when iterating over the {@link java.util.Collection}.
*
* @return a {@link java.util.Collection} of {@link java.util.Map}s that relate fields to values
*/
Collection<Map<String, String>> readFile();
/**
* Overwrites the file's contents with the data passed to this method, in the file's format.
*
* @param data a {@link java.util.Collection} of {@link java.util.Map}s that relate fields to values; see
* {@link #readFile()} for a description of this data structure
* @return {@code true} if the file was successfully written to; {@code false} otherwise
*/
boolean writeFile(Collection<Map<String, String>> data);
/**
* Provides a collection of unique field names. If the file has not been read from nor written to, there are no
* guarantees that the returned {@link java.util.Set} contains an accurate collection of field names. Otherwise, the
* {@link java.util.Set} will contain the fields names that are current as of the last file access.
*
* @return a {@link java.util.Set} of the file's field names
*/
Set<String> getFields();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment