See the previous iteration. I have incorporated the answer of h.j.k.. Now I have:
LineStringSerializationFactory.java:
package net.coderodde.lists.serial;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Scanner;
/**
* This class contains static methods for serializing the lists of elements to
* a textual representation and deserializing it back to the list of elements.
*
* @author Rodion "rodde" Efremov
* @version 1.61
*/
public class LineStringSerializationFactory {
/**
* The alias for the new line string.
*/
private static final String ENDL = "\n";
// Do not instantiate this class.
private LineStringSerializationFactory() {}
/**
* Serializes the elements in <code>list</code>. The <code>serializer</code>
* is supposed to return a single line of text with no new line characters.
* That string is supposed to encode the state of the serialized element.
* The order of encoding lines is dictated by the iteration order of the
* input list.
*
* <b>Note:</b> this serialization procedure assumes that
* <code>serializer</code> does not map any element to a string containing
* a new line character as it is used for separating the element encodings.
*
* @param <E> the actual type of elements to serialize.
* @param collection the collection of elements to serialize.
* @param serializer the serializer returning a line of text encoding the
* state of the input element.
* @return a string each line of which encodes a single element.
*
* @throws IllegalArgumentException if <code>serializer</code> returns a
* string containing a new line character.
*/
public static <E> String serialize(Collection<E> collection,
LineStringSerializer<E> serializer) {
StringBuilder sb = new StringBuilder();
for (E element : collection) {
String line = serializer.serialize(element);
if (line.contains(ENDL)) {
throw new IllegalArgumentException(
"The line serializer may not return the new line " +
"character in its output.");
}
sb.append(line).append(ENDL);
}
return sb.toString();
}
/**
* Deserializes the list from the input text <code>text</code>. Each line
* is expected to produce exactly one element.
*
* @param <E> the actual deserialized element type.
* @param text the entire string holding the encoding of the entire
* list.
* @param deserializer the deserializer converting each input line to an
* element whose state is encoded by that line.
* @return the list of elements encoded by <code>text</code> in
* the same order as their respective encoding lines.
*/
public static <E> List<E>
deserialize(String text, LineStringDeserializer<E> deserializer) {
List<E> ret = new ArrayList<>();
Scanner scanner = new Scanner(text);
while (scanner.hasNextLine()) {
ret.add(deserializer.deserialize(scanner.nextLine()));
}
scanner.close();
return ret;
}
}
LineStringSerializer.java:
package net.coderodde.lists.serial;
/**
* This interface defines the API for serializing an object to a string.
*
* @author Rodion "rodde" Efremov
* @version 1.61
* @param <E> the object type.
*/
@FunctionalInterface
public interface LineStringSerializer<E> {
/**
* Returns the textual representation of the input object.
*
* @param object the object to serialize.
* @return the textual representation of the input object.
*/
public String serialize(E object);
}
LineStringDeserializer.java:
package net.coderodde.lists.serial;
/**
* This interface defines the API for deserializing the objects from their
* textual representation.
*
* @author Rodion "rodde" Efremov
* @version 1.61
* @param <E> the object type.
*/
@FunctionalInterface
public interface LineStringDeserializer<E> {
/**
* Deserializes an object from its textual representation.
*
* @param text the string representing the state of the object.
* @return the actual, deserialized object.
*/
public E deserialize(String text);
}
LineStringSerializationFactoryTest.java:
package net.coderodde.lists.serial;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
public class LineStringSerializationFactoryTest {
private static Random random;
@BeforeClass
public static void init() {
long seed = System.currentTimeMillis();
System.out.println("Seed: " + seed);
random = new Random(seed);
}
@Test
public void testSimpleIntegers() {
List<Integer> input = getRandomIntegerList(1000, random);
String text = LineStringSerializationFactory
.serialize(input, Object::toString);
List<Integer> output = LineStringSerializationFactory
.deserialize(text, Integer::parseInt);
assertTrue(input.equals(output));
}
@Test
public void testListOfLists() {
// Create data to serialize.
List<List<Integer>> input = getRandomListOfLists(1000, random);
// Serialize it.
String text = LineStringSerializationFactory
.serialize(input, new IntListSerializer());
// Deserialize it.
List<List<Integer>> output =
LineStringSerializationFactory
.deserialize(text, new IntListDeserializer());
// Compare.
assertTrue(input.equals(output));
}
/**
* Constructs a random integer array.
*
* @param size the length of the integer array.
* @param random the random number generator.
* @return the integer array.
*/
private static List<Integer>
getRandomIntegerList(int size, Random random) {
return random.ints(size).boxed().collect(Collectors.toList());
}
/**
* Constructs a random list of integer lists.
*
* @param size the length of the outer list.
* @param random the random number generator.
* @return the random list of integer lists.
*/
private static List<List<Integer>>
getRandomListOfLists(int size, Random random) {
List<List<Integer>> ret = new ArrayList<>(size);
for (int i = 0; i < size; ++i) {
ret.add(getRandomIntegerList(random.nextInt(50), random));
}
return ret;
}
private static class IntListSerializer
implements LineStringSerializer<List<Integer>> {
@Override
public String serialize(List<Integer> list) {
StringBuilder sb = new StringBuilder();
int index = 0;
for (Integer i : list) {
sb.append(i.toString());
if (index < list.size() - 1) {
sb.append(",");
}
}
return sb.toString();
}
}
private static class IntListDeserializer
implements LineStringDeserializer<List<Integer>> {
@Override
public List<Integer> deserialize(String text) {
return Stream.of(text.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(LineStringSerializationFactoryTest::asInteger)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
private static Integer asInteger(String value) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException ex) {
return null;
}
}
}
So, what do you think?