From c076099ddd3dadcee5f694f3ce7fcc22771fa7b0 Mon Sep 17 00:00:00 2001 From: Jonathan Wood Date: Sat, 27 Jun 2015 12:50:15 -0700 Subject: [PATCH] Use 'write' rather than 'serialize'. Also refactor ValueWriter implementations into ValueConverter implementations, where possible. --- ...ySerializer.java => ArrayValueWriter.java} | 6 +- .../moandjiezana/toml/BooleanConverter.java | 22 ++++++- .../moandjiezana/toml/BooleanSerializer.java | 25 ------- .../moandjiezana/toml/BooleanValueWriter.java | 25 +++++++ .../com/moandjiezana/toml/DateConverter.java | 31 ++++++++- ...teSerializer.java => DateValueWriter.java} | 12 ++-- ...MapSerializer.java => MapValueWriter.java} | 42 ++++++------ .../moandjiezana/toml/NumberConverter.java | 23 ++++++- .../moandjiezana/toml/NumberSerializer.java | 25 ------- .../moandjiezana/toml/NumberValueWriter.java | 25 +++++++ ...Serializer.java => ObjectValueWriter.java} | 12 ++-- .../toml/PrimitiveArraySerializer.java | 28 -------- .../toml/PrimitiveArrayValueWriter.java | 28 ++++++++ .../com/moandjiezana/toml/Serializer.java | 11 ---- .../moandjiezana/toml/SerializerContext.java | 50 -------------- .../com/moandjiezana/toml/Serializers.java | 38 ----------- .../moandjiezana/toml/StringConverter.java | 55 +++++++++++++++- ...Serializer.java => StringValueWriter.java} | 14 ++-- .../toml/TableArraySerializer.java | 23 ------- .../toml/TableArrayValueWriter.java | 23 +++++++ src/main/java/com/moandjiezana/toml/Toml.java | 29 +++----- .../com/moandjiezana/toml/ValueWriter.java | 11 ++++ .../com/moandjiezana/toml/ValueWriters.java | 41 ++++++++++++ .../com/moandjiezana/toml/WriterContext.java | 50 ++++++++++++++ ...rializerTest.java => ValueWriterTest.java} | 66 +++++++++---------- 25 files changed, 412 insertions(+), 303 deletions(-) rename src/main/java/com/moandjiezana/toml/{ArraySerializer.java => ArrayValueWriter.java} (88%) delete mode 100644 src/main/java/com/moandjiezana/toml/BooleanSerializer.java create mode 100644 src/main/java/com/moandjiezana/toml/BooleanValueWriter.java rename src/main/java/com/moandjiezana/toml/{DateSerializer.java => DateValueWriter.java} (62%) rename src/main/java/com/moandjiezana/toml/{MapSerializer.java => MapValueWriter.java} (54%) delete mode 100644 src/main/java/com/moandjiezana/toml/NumberSerializer.java create mode 100644 src/main/java/com/moandjiezana/toml/NumberValueWriter.java rename src/main/java/com/moandjiezana/toml/{ObjectSerializer.java => ObjectValueWriter.java} (82%) delete mode 100644 src/main/java/com/moandjiezana/toml/PrimitiveArraySerializer.java create mode 100644 src/main/java/com/moandjiezana/toml/PrimitiveArrayValueWriter.java delete mode 100644 src/main/java/com/moandjiezana/toml/Serializer.java delete mode 100644 src/main/java/com/moandjiezana/toml/SerializerContext.java delete mode 100644 src/main/java/com/moandjiezana/toml/Serializers.java rename src/main/java/com/moandjiezana/toml/{StringSerializer.java => StringValueWriter.java} (79%) delete mode 100644 src/main/java/com/moandjiezana/toml/TableArraySerializer.java create mode 100644 src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java create mode 100644 src/main/java/com/moandjiezana/toml/ValueWriter.java create mode 100644 src/main/java/com/moandjiezana/toml/ValueWriters.java create mode 100644 src/main/java/com/moandjiezana/toml/WriterContext.java rename src/test/java/com/moandjiezana/toml/{SerializerTest.java => ValueWriterTest.java} (77%) diff --git a/src/main/java/com/moandjiezana/toml/ArraySerializer.java b/src/main/java/com/moandjiezana/toml/ArrayValueWriter.java similarity index 88% rename from src/main/java/com/moandjiezana/toml/ArraySerializer.java rename to src/main/java/com/moandjiezana/toml/ArrayValueWriter.java index c396b3a..f474ab9 100644 --- a/src/main/java/com/moandjiezana/toml/ArraySerializer.java +++ b/src/main/java/com/moandjiezana/toml/ArrayValueWriter.java @@ -5,7 +5,7 @@ import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; -abstract class ArraySerializer implements Serializer { +abstract class ArrayValueWriter implements ValueWriter { static protected boolean isArrayish(Object value) { return value instanceof Collection || value.getClass().isArray(); } @@ -23,8 +23,8 @@ abstract class ArraySerializer implements Serializer { static boolean isArrayOfPrimitive(Object array) { Object first = peek(array); if (first != null) { - Serializer serializer = Serializers.findSerializerFor(first); - return serializer.isPrimitiveType() || isArrayish(first); + ValueWriter valueWriter = ValueWriters.findWriterFor(first); + return valueWriter.isPrimitiveType() || isArrayish(first); } return false; diff --git a/src/main/java/com/moandjiezana/toml/BooleanConverter.java b/src/main/java/com/moandjiezana/toml/BooleanConverter.java index 82f73d2..68bc7b0 100644 --- a/src/main/java/com/moandjiezana/toml/BooleanConverter.java +++ b/src/main/java/com/moandjiezana/toml/BooleanConverter.java @@ -3,7 +3,7 @@ package com.moandjiezana.toml; import java.util.concurrent.atomic.AtomicInteger; -class BooleanConverter implements ValueConverter { +class BooleanConverter implements ValueConverter, ValueWriter { static final BooleanConverter BOOLEAN_PARSER = new BooleanConverter(); @@ -24,5 +24,25 @@ class BooleanConverter implements ValueConverter { return b; } + @Override + public boolean canWrite(Object value) { + return Boolean.class.isInstance(value); + } + + @Override + public void write(Object value, WriterContext context) { + context.output.append(value.toString()); + } + + @Override + public boolean isPrimitiveType() { + return true; + } + + @Override + public boolean isTable() { + return false; + } + private BooleanConverter() {} } diff --git a/src/main/java/com/moandjiezana/toml/BooleanSerializer.java b/src/main/java/com/moandjiezana/toml/BooleanSerializer.java deleted file mode 100644 index 022ac20..0000000 --- a/src/main/java/com/moandjiezana/toml/BooleanSerializer.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.moandjiezana.toml; - -class BooleanSerializer implements Serializer { - static final Serializer BOOLEAN_SERIALIZER = new BooleanSerializer(); - - @Override - public boolean canSerialize(Object value) { - return Boolean.class.isInstance(value); - } - - @Override - public void serialize(Object value, SerializerContext context) { - context.serialized.append(value.toString()); - } - - @Override - public boolean isPrimitiveType() { - return true; - } - - @Override - public boolean isTable() { - return false; - } -} diff --git a/src/main/java/com/moandjiezana/toml/BooleanValueWriter.java b/src/main/java/com/moandjiezana/toml/BooleanValueWriter.java new file mode 100644 index 0000000..7a230bb --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/BooleanValueWriter.java @@ -0,0 +1,25 @@ +package com.moandjiezana.toml; + +class BooleanValueWriter implements ValueWriter { + static final ValueWriter BOOLEAN_VALUE_WRITER = new BooleanValueWriter(); + + @Override + public boolean canWrite(Object value) { + return Boolean.class.isInstance(value); + } + + @Override + public void write(Object value, WriterContext context) { + context.output.append(value.toString()); + } + + @Override + public boolean isPrimitiveType() { + return true; + } + + @Override + public boolean isTable() { + return false; + } +} diff --git a/src/main/java/com/moandjiezana/toml/DateConverter.java b/src/main/java/com/moandjiezana/toml/DateConverter.java index 2063d46..07761b0 100644 --- a/src/main/java/com/moandjiezana/toml/DateConverter.java +++ b/src/main/java/com/moandjiezana/toml/DateConverter.java @@ -1,14 +1,18 @@ package com.moandjiezana.toml; import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -class DateConverter implements ValueConverter { +class DateConverter implements ValueConverter, ValueWriter { static final DateConverter DATE_PARSER = new DateConverter(); private static final Pattern DATE_REGEX = Pattern.compile("(\\d{4}-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9])(\\.\\d*)?(Z|(?:[+\\-]\\d{2}:\\d{2}))(.*)"); + private static final Calendar calendar = new GregorianCalendar(); @Override public boolean canConvert(String s) { @@ -79,6 +83,29 @@ class DateConverter implements ValueConverter { return errors; } } - + + @Override + public boolean canWrite(Object value) { + return value instanceof Date; + } + + @Override + public void write(Object value, WriterContext context) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:m:ss"); + context.output.append(dateFormat.format(value)); + int tzOffset = (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / (60 * 1000); + context.output.append(String.format("%+03d:%02d", tzOffset / 60, tzOffset % 60)); + } + + @Override + public boolean isPrimitiveType() { + return true; + } + + @Override + public boolean isTable() { + return false; + } + private DateConverter() {} } diff --git a/src/main/java/com/moandjiezana/toml/DateSerializer.java b/src/main/java/com/moandjiezana/toml/DateValueWriter.java similarity index 62% rename from src/main/java/com/moandjiezana/toml/DateSerializer.java rename to src/main/java/com/moandjiezana/toml/DateValueWriter.java index 0da2ba9..dd7b1cd 100644 --- a/src/main/java/com/moandjiezana/toml/DateSerializer.java +++ b/src/main/java/com/moandjiezana/toml/DateValueWriter.java @@ -5,21 +5,21 @@ import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; -class DateSerializer implements Serializer { - static final Serializer DATE_SERIALIZER = new DateSerializer(); +class DateValueWriter implements ValueWriter { + static final ValueWriter DATE_VALUE_WRITER = new DateValueWriter(); private static final Calendar calendar = new GregorianCalendar(); @Override - public boolean canSerialize(Object value) { + public boolean canWrite(Object value) { return value instanceof Date; } @Override - public void serialize(Object value, SerializerContext context) { + public void write(Object value, WriterContext context) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:m:ss"); - context.serialized.append(dateFormat.format(value)); + context.output.append(dateFormat.format(value)); int tzOffset = (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / (60 * 1000); - context.serialized.append(String.format("%+03d:%02d", tzOffset / 60, tzOffset % 60)); + context.output.append(String.format("%+03d:%02d", tzOffset / 60, tzOffset % 60)); } @Override diff --git a/src/main/java/com/moandjiezana/toml/MapSerializer.java b/src/main/java/com/moandjiezana/toml/MapValueWriter.java similarity index 54% rename from src/main/java/com/moandjiezana/toml/MapSerializer.java rename to src/main/java/com/moandjiezana/toml/MapValueWriter.java index bd7b30e..717d18f 100644 --- a/src/main/java/com/moandjiezana/toml/MapSerializer.java +++ b/src/main/java/com/moandjiezana/toml/MapValueWriter.java @@ -4,25 +4,25 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static com.moandjiezana.toml.PrimitiveArraySerializer.PRIMITIVE_ARRAY_SERIALIZER; -import static com.moandjiezana.toml.TableArraySerializer.TABLE_ARRAY_SERIALIZER; +import static com.moandjiezana.toml.PrimitiveArrayValueWriter.PRIMITIVE_ARRAY_VALUE_WRITER; +import static com.moandjiezana.toml.TableArrayValueWriter.TABLE_ARRAY_VALUE_WRITER; -class MapSerializer implements Serializer { - static final Serializer MAP_SERIALIZER = new MapSerializer(); +class MapValueWriter implements ValueWriter { + static final ValueWriter MAP_VALUE_WRITER = new MapValueWriter(); private static final Pattern requiredQuotingPattern = Pattern.compile("^.*[^A-Za-z\\d_-].*$"); @Override - public boolean canSerialize(Object value) { + public boolean canWrite(Object value) { return value instanceof Map; } @Override - public void serialize(Object value, SerializerContext context) { + public void write(Object value, WriterContext context) { Map from = (Map) value; if (hasPrimitiveValues(from)) { - context.serializeKey(); + context.writeKey(); } // Render primitive types and arrays of primitive first so they are @@ -33,16 +33,16 @@ class MapSerializer implements Serializer { continue; } - Serializer serializer = Serializers.findSerializerFor(fromValue); - if (serializer.isPrimitiveType()) { + ValueWriter valueWriter = ValueWriters.findWriterFor(fromValue); + if (valueWriter.isPrimitiveType()) { context.indent(); - context.serialized.append(quoteKey(key)).append(" = "); - serializer.serialize(fromValue, context); - context.serialized.append('\n'); - } else if (serializer == PRIMITIVE_ARRAY_SERIALIZER) { - context.serialized.append(quoteKey(key)).append(" = "); - serializer.serialize(fromValue, context); - context.serialized.append('\n'); + context.output.append(quoteKey(key)).append(" = "); + valueWriter.write(fromValue, context); + context.output.append('\n'); + } else if (valueWriter == PRIMITIVE_ARRAY_VALUE_WRITER) { + context.output.append(quoteKey(key)).append(" = "); + valueWriter.write(fromValue, context); + context.output.append('\n'); } } @@ -53,9 +53,9 @@ class MapSerializer implements Serializer { continue; } - Serializer serializer = Serializers.findSerializerFor(fromValue); - if (serializer.isTable() || serializer == TABLE_ARRAY_SERIALIZER) { - serializer.serialize(fromValue, context.extend(quoteKey(key))); + ValueWriter valueWriter = ValueWriters.findWriterFor(fromValue); + if (valueWriter.isTable() || valueWriter == TABLE_ARRAY_VALUE_WRITER) { + valueWriter.write(fromValue, context.extend(quoteKey(key))); } } } @@ -87,8 +87,8 @@ class MapSerializer implements Serializer { continue; } - Serializer serializer = Serializers.findSerializerFor(fromValue); - if (serializer.isPrimitiveType() || serializer == PRIMITIVE_ARRAY_SERIALIZER) { + ValueWriter valueWriter = ValueWriters.findWriterFor(fromValue); + if (valueWriter.isPrimitiveType() || valueWriter == PRIMITIVE_ARRAY_VALUE_WRITER) { return true; } } diff --git a/src/main/java/com/moandjiezana/toml/NumberConverter.java b/src/main/java/com/moandjiezana/toml/NumberConverter.java index a65578c..74a2edf 100644 --- a/src/main/java/com/moandjiezana/toml/NumberConverter.java +++ b/src/main/java/com/moandjiezana/toml/NumberConverter.java @@ -2,7 +2,7 @@ package com.moandjiezana.toml; import java.util.concurrent.atomic.AtomicInteger; -class NumberConverter implements ValueConverter { +class NumberConverter implements ValueConverter, ValueWriter { static final NumberConverter NUMBER_PARSER = new NumberConverter(); @Override @@ -82,4 +82,25 @@ class NumberConverter implements ValueConverter { return errors; } } + + @Override + public boolean canWrite(Object value) { + return Number.class.isInstance(value); + } + + @Override + public void write(Object value, WriterContext context) { + context.output.append(value.toString()); + } + + @Override + public boolean isPrimitiveType() { + return true; + } + + @Override + public boolean isTable() { + return false; + } + } diff --git a/src/main/java/com/moandjiezana/toml/NumberSerializer.java b/src/main/java/com/moandjiezana/toml/NumberSerializer.java deleted file mode 100644 index 78eab87..0000000 --- a/src/main/java/com/moandjiezana/toml/NumberSerializer.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.moandjiezana.toml; - -class NumberSerializer implements Serializer { - static final Serializer NUMBER_SERIALIZER = new NumberSerializer(); - - @Override - public boolean canSerialize(Object value) { - return Number.class.isInstance(value); - } - - @Override - public void serialize(Object value, SerializerContext context) { - context.serialized.append(value.toString()); - } - - @Override - public boolean isPrimitiveType() { - return true; - } - - @Override - public boolean isTable() { - return false; - } -} diff --git a/src/main/java/com/moandjiezana/toml/NumberValueWriter.java b/src/main/java/com/moandjiezana/toml/NumberValueWriter.java new file mode 100644 index 0000000..48c0bad --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/NumberValueWriter.java @@ -0,0 +1,25 @@ +package com.moandjiezana.toml; + +class NumberValueWriter implements ValueWriter { + static final ValueWriter NUMBER_VALUE_WRITER = new NumberValueWriter(); + + @Override + public boolean canWrite(Object value) { + return Number.class.isInstance(value); + } + + @Override + public void write(Object value, WriterContext context) { + context.output.append(value.toString()); + } + + @Override + public boolean isPrimitiveType() { + return true; + } + + @Override + public boolean isTable() { + return false; + } +} diff --git a/src/main/java/com/moandjiezana/toml/ObjectSerializer.java b/src/main/java/com/moandjiezana/toml/ObjectValueWriter.java similarity index 82% rename from src/main/java/com/moandjiezana/toml/ObjectSerializer.java rename to src/main/java/com/moandjiezana/toml/ObjectValueWriter.java index 0540c38..1c37e6a 100644 --- a/src/main/java/com/moandjiezana/toml/ObjectSerializer.java +++ b/src/main/java/com/moandjiezana/toml/ObjectValueWriter.java @@ -4,25 +4,25 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; -import static com.moandjiezana.toml.MapSerializer.MAP_SERIALIZER; +import static com.moandjiezana.toml.MapValueWriter.MAP_VALUE_WRITER; -class ObjectSerializer implements Serializer { - static final Serializer OBJECT_SERIALIZER = new ObjectSerializer(); +class ObjectValueWriter implements ValueWriter { + static final ValueWriter OBJECT_VALUE_WRITER = new ObjectValueWriter(); @Override - public boolean canSerialize(Object value) { + public boolean canWrite(Object value) { return true; } @Override - public void serialize(Object value, SerializerContext context) { + public void write(Object value, WriterContext context) { Map to = new LinkedHashMap(); Set fields = getFieldsForClass(value.getClass()); for (Field field : fields) { to.put(field.getName(), getFieldValue(field, value)); } - MAP_SERIALIZER.serialize(to, context); + MAP_VALUE_WRITER.write(to, context); } @Override diff --git a/src/main/java/com/moandjiezana/toml/PrimitiveArraySerializer.java b/src/main/java/com/moandjiezana/toml/PrimitiveArraySerializer.java deleted file mode 100644 index 79be5ab..0000000 --- a/src/main/java/com/moandjiezana/toml/PrimitiveArraySerializer.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.moandjiezana.toml; - -import java.util.Collection; - -class PrimitiveArraySerializer extends ArraySerializer { - static final Serializer PRIMITIVE_ARRAY_SERIALIZER = new PrimitiveArraySerializer(); - - @Override - public boolean canSerialize(Object value) { - return isArrayish(value) && isArrayOfPrimitive(value); - } - - @Override - public void serialize(Object value, SerializerContext context) { - Collection values = normalize(value); - - context.serialized.append("[ "); - boolean first = true; - for (Object elem : values) { - if (!first) { - context.serialized.append(", "); - } - Serializers.serialize(elem, context); - first = false; - } - context.serialized.append(" ]"); - } -} diff --git a/src/main/java/com/moandjiezana/toml/PrimitiveArrayValueWriter.java b/src/main/java/com/moandjiezana/toml/PrimitiveArrayValueWriter.java new file mode 100644 index 0000000..e0e3aa7 --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/PrimitiveArrayValueWriter.java @@ -0,0 +1,28 @@ +package com.moandjiezana.toml; + +import java.util.Collection; + +class PrimitiveArrayValueWriter extends ArrayValueWriter { + static final ValueWriter PRIMITIVE_ARRAY_VALUE_WRITER = new PrimitiveArrayValueWriter(); + + @Override + public boolean canWrite(Object value) { + return isArrayish(value) && isArrayOfPrimitive(value); + } + + @Override + public void write(Object value, WriterContext context) { + Collection values = normalize(value); + + context.output.append("[ "); + boolean first = true; + for (Object elem : values) { + if (!first) { + context.output.append(", "); + } + ValueWriters.write(elem, context); + first = false; + } + context.output.append(" ]"); + } +} diff --git a/src/main/java/com/moandjiezana/toml/Serializer.java b/src/main/java/com/moandjiezana/toml/Serializer.java deleted file mode 100644 index c0ef999..0000000 --- a/src/main/java/com/moandjiezana/toml/Serializer.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.moandjiezana.toml; - -interface Serializer { - boolean canSerialize(Object value); - - void serialize(Object value, SerializerContext context); - - boolean isPrimitiveType(); - - boolean isTable(); -} diff --git a/src/main/java/com/moandjiezana/toml/SerializerContext.java b/src/main/java/com/moandjiezana/toml/SerializerContext.java deleted file mode 100644 index a83434b..0000000 --- a/src/main/java/com/moandjiezana/toml/SerializerContext.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.moandjiezana.toml; - -class SerializerContext { - private String key = ""; - private boolean isArrayOfTable = false; - StringBuilder serialized = new StringBuilder(); - - SerializerContext(String key, StringBuilder serialized) { - this.key = key; - this.serialized = serialized; - } - - SerializerContext() { - } - - SerializerContext extend(String newKey) { - String fullKey = key + (key.isEmpty() ? newKey : "." + newKey); - - return new SerializerContext(fullKey, serialized); - } - - SerializerContext extend() { - return new SerializerContext(key, serialized); - } - - void serializeKey() { - if (key.isEmpty()) { - return; - } - - if (serialized.length() > 0) { - serialized.append('\n'); - } - - if (isArrayOfTable) { - serialized.append("[[").append(key).append("]]\n"); - } else { - serialized.append('[').append(key).append("]\n"); - } - } - - void indent() { - serialized.append(key.isEmpty() ? "" : " "); - } - - SerializerContext setIsArrayOfTable(boolean isArrayOfTable) { - this.isArrayOfTable = isArrayOfTable; - return this; - } -} diff --git a/src/main/java/com/moandjiezana/toml/Serializers.java b/src/main/java/com/moandjiezana/toml/Serializers.java deleted file mode 100644 index fb49757..0000000 --- a/src/main/java/com/moandjiezana/toml/Serializers.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.moandjiezana.toml; - -import static com.moandjiezana.toml.BooleanSerializer.BOOLEAN_SERIALIZER; -import static com.moandjiezana.toml.DateSerializer.DATE_SERIALIZER; -import static com.moandjiezana.toml.MapSerializer.MAP_SERIALIZER; -import static com.moandjiezana.toml.NumberSerializer.NUMBER_SERIALIZER; -import static com.moandjiezana.toml.ObjectSerializer.OBJECT_SERIALIZER; -import static com.moandjiezana.toml.PrimitiveArraySerializer.PRIMITIVE_ARRAY_SERIALIZER; -import static com.moandjiezana.toml.StringSerializer.STRING_SERIALIZER; -import static com.moandjiezana.toml.TableArraySerializer.TABLE_ARRAY_SERIALIZER; - -abstract class Serializers { - private static final Serializer[] SERIALIZERS = { - STRING_SERIALIZER, NUMBER_SERIALIZER, BOOLEAN_SERIALIZER, DATE_SERIALIZER, - MAP_SERIALIZER, PRIMITIVE_ARRAY_SERIALIZER, TABLE_ARRAY_SERIALIZER - }; - - static Serializer findSerializerFor(Object value) { - for (Serializer serializer : SERIALIZERS) { - if (serializer.canSerialize(value)) { - return serializer; - } - } - - return OBJECT_SERIALIZER; - } - - static String serialize(Object value) { - SerializerContext context = new SerializerContext(); - serialize(value, context); - - return context.serialized.toString(); - } - - static void serialize(Object value, SerializerContext context) { - findSerializerFor(value).serialize(value, context); - } -} diff --git a/src/main/java/com/moandjiezana/toml/StringConverter.java b/src/main/java/com/moandjiezana/toml/StringConverter.java index 8100e44..774e9c3 100644 --- a/src/main/java/com/moandjiezana/toml/StringConverter.java +++ b/src/main/java/com/moandjiezana/toml/StringConverter.java @@ -4,11 +4,23 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -class StringConverter implements ValueConverter { +class StringConverter implements ValueConverter, ValueWriter { static final StringConverter STRING_PARSER = new StringConverter(); private static final Pattern UNICODE_REGEX = Pattern.compile("\\\\[uU](.{4})"); + static private final String[] specialCharacterEscapes = new String[93]; + + static { + specialCharacterEscapes[0x08] = "\\b"; + specialCharacterEscapes[0x09] = "\\t"; + specialCharacterEscapes[0x0A] = "\\n"; + specialCharacterEscapes[0x0C] = "\\f"; + specialCharacterEscapes[0x0D] = "\\r"; + specialCharacterEscapes[0x22] = "\\\""; + specialCharacterEscapes[0x5C] = "\\"; + } + @Override public boolean canConvert(String s) { return s.startsWith("\""); @@ -76,6 +88,45 @@ class StringConverter implements ValueConverter { .replace("\\b", "\b") .replace("\\f", "\f"); } - + + @Override + public boolean canWrite(Object value) { + return value.getClass().isAssignableFrom(String.class); + } + + @Override + public void write(Object value, WriterContext context) { + context.output.append('"'); + escapeUnicode(value.toString(), context.output); + context.output.append('"'); + } + + @Override + public boolean isPrimitiveType() { + return true; + } + + @Override + public boolean isTable() { + return false; + } + + private void escapeUnicode(String in, StringBuilder out) { + for (int i = 0; i < in.length(); i++) { + int codePoint = in.codePointAt(i); + if (codePoint < specialCharacterEscapes.length && specialCharacterEscapes[codePoint] != null) { + out.append(specialCharacterEscapes[codePoint]); + } else if (codePoint > 0x1f && codePoint < 0x7f) { + out.append(Character.toChars(codePoint)); + } else if (codePoint <= 0xFFFF) { + out.append(String.format("\\u%04X", codePoint)); + } else { + out.append(String.format("\\U%08X", codePoint)); + // Skip the low surrogate, which will be the next in the code point sequence. + i++; + } + } + } + private StringConverter() {} } diff --git a/src/main/java/com/moandjiezana/toml/StringSerializer.java b/src/main/java/com/moandjiezana/toml/StringValueWriter.java similarity index 79% rename from src/main/java/com/moandjiezana/toml/StringSerializer.java rename to src/main/java/com/moandjiezana/toml/StringValueWriter.java index d3eee57..acdd79b 100644 --- a/src/main/java/com/moandjiezana/toml/StringSerializer.java +++ b/src/main/java/com/moandjiezana/toml/StringValueWriter.java @@ -1,7 +1,7 @@ package com.moandjiezana.toml; -class StringSerializer implements Serializer { - static final Serializer STRING_SERIALIZER = new StringSerializer(); +class StringValueWriter implements ValueWriter { + static final ValueWriter STRING_VALUE_WRITER = new StringValueWriter(); static private final String[] specialCharacterEscapes = new String[93]; @@ -16,15 +16,15 @@ class StringSerializer implements Serializer { } @Override - public boolean canSerialize(Object value) { + public boolean canWrite(Object value) { return value.getClass().isAssignableFrom(String.class); } @Override - public void serialize(Object value, SerializerContext context) { - context.serialized.append('"'); - escapeUnicode(value.toString(), context.serialized); - context.serialized.append('"'); + public void write(Object value, WriterContext context) { + context.output.append('"'); + escapeUnicode(value.toString(), context.output); + context.output.append('"'); } @Override diff --git a/src/main/java/com/moandjiezana/toml/TableArraySerializer.java b/src/main/java/com/moandjiezana/toml/TableArraySerializer.java deleted file mode 100644 index d2c2912..0000000 --- a/src/main/java/com/moandjiezana/toml/TableArraySerializer.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.moandjiezana.toml; - -import java.util.Collection; - -class TableArraySerializer extends ArraySerializer { - static final Serializer TABLE_ARRAY_SERIALIZER = new TableArraySerializer(); - - @Override - public boolean canSerialize(Object value) { - return isArrayish(value) && !isArrayOfPrimitive(value); - } - - @Override - public void serialize(Object value, SerializerContext context) { - Collection values = normalize(value); - - SerializerContext subContext = context.extend().setIsArrayOfTable(true); - - for (Object elem : values) { - Serializers.serialize(elem, subContext); - } - } -} diff --git a/src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java b/src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java new file mode 100644 index 0000000..9fdd9b6 --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/TableArrayValueWriter.java @@ -0,0 +1,23 @@ +package com.moandjiezana.toml; + +import java.util.Collection; + +class TableArrayValueWriter extends ArrayValueWriter { + static final ValueWriter TABLE_ARRAY_VALUE_WRITER = new TableArrayValueWriter(); + + @Override + public boolean canWrite(Object value) { + return isArrayish(value) && !isArrayOfPrimitive(value); + } + + @Override + public void write(Object value, WriterContext context) { + Collection values = normalize(value); + + WriterContext subContext = context.extend().setIsArrayOfTable(true); + + for (Object elem : values) { + ValueWriters.write(elem, subContext); + } + } +} diff --git a/src/main/java/com/moandjiezana/toml/Toml.java b/src/main/java/com/moandjiezana/toml/Toml.java index d5efe3f..715b206 100644 --- a/src/main/java/com/moandjiezana/toml/Toml.java +++ b/src/main/java/com/moandjiezana/toml/Toml.java @@ -1,24 +1,11 @@ package com.moandjiezana.toml; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - import com.google.gson.Gson; import com.google.gson.JsonElement; +import java.io.*; +import java.util.*; + /** *

Provides access to the keys and tables in a TOML data source.

* @@ -378,7 +365,7 @@ public class Toml { * @return a string containing the TOML representation of this Toml instance. */ public String serialize() { - return Serializers.serialize(values); + return ValueWriters.write(values); } /** @@ -386,13 +373,13 @@ public class Toml { * * The input can comprise arbitrarily nested combinations of Java primitive types, * other {@link Object}s, {@link Map}s, {@link List}s, and Arrays. {@link Object}s and {@link Map}s - * are serialized to TOML tables, and {@link List}s and Array to TOML arrays. + * are output to TOML tables, and {@link List}s and Array to TOML arrays. * - * @param from the object to be serialized + * @param from the object to be written * @return a string containing the TOML representation of the given Object */ - public static String serializeFrom(Object from) { - return Serializers.serialize(from); + public static String write(Object from) { + return ValueWriters.write(from); } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/moandjiezana/toml/ValueWriter.java b/src/main/java/com/moandjiezana/toml/ValueWriter.java new file mode 100644 index 0000000..6edae56 --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/ValueWriter.java @@ -0,0 +1,11 @@ +package com.moandjiezana.toml; + +interface ValueWriter { + boolean canWrite(Object value); + + void write(Object value, WriterContext context); + + boolean isPrimitiveType(); + + boolean isTable(); +} diff --git a/src/main/java/com/moandjiezana/toml/ValueWriters.java b/src/main/java/com/moandjiezana/toml/ValueWriters.java new file mode 100644 index 0000000..9ffe6ba --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/ValueWriters.java @@ -0,0 +1,41 @@ +package com.moandjiezana.toml; + +import static com.moandjiezana.toml.BooleanConverter.BOOLEAN_PARSER; +import static com.moandjiezana.toml.DateConverter.DATE_PARSER; +import static com.moandjiezana.toml.MapValueWriter.MAP_VALUE_WRITER; +import static com.moandjiezana.toml.NumberConverter.NUMBER_PARSER; +import static com.moandjiezana.toml.ObjectValueWriter.OBJECT_VALUE_WRITER; +import static com.moandjiezana.toml.PrimitiveArrayValueWriter.PRIMITIVE_ARRAY_VALUE_WRITER; +import static com.moandjiezana.toml.StringConverter.STRING_PARSER; +import static com.moandjiezana.toml.TableArrayValueWriter.TABLE_ARRAY_VALUE_WRITER; + +class ValueWriters { + + static ValueWriter findWriterFor(Object value) { + for (ValueWriter valueWriter : VALUE_WRITERs) { + if (valueWriter.canWrite(value)) { + return valueWriter; + } + } + + return OBJECT_VALUE_WRITER; + } + + static String write(Object value) { + WriterContext context = new WriterContext(); + write(value, context); + + return context.output.toString(); + } + + static void write(Object value, WriterContext context) { + findWriterFor(value).write(value, context); + } + + private ValueWriters() {} + + private static final ValueWriter[] VALUE_WRITERs = { + STRING_PARSER, NUMBER_PARSER, BOOLEAN_PARSER, DATE_PARSER, + MAP_VALUE_WRITER, PRIMITIVE_ARRAY_VALUE_WRITER, TABLE_ARRAY_VALUE_WRITER + }; +} diff --git a/src/main/java/com/moandjiezana/toml/WriterContext.java b/src/main/java/com/moandjiezana/toml/WriterContext.java new file mode 100644 index 0000000..e07e828 --- /dev/null +++ b/src/main/java/com/moandjiezana/toml/WriterContext.java @@ -0,0 +1,50 @@ +package com.moandjiezana.toml; + +class WriterContext { + private String key = ""; + private boolean isArrayOfTable = false; + StringBuilder output = new StringBuilder(); + + WriterContext(String key, StringBuilder output) { + this.key = key; + this.output = output; + } + + WriterContext() { + } + + WriterContext extend(String newKey) { + String fullKey = key + (key.isEmpty() ? newKey : "." + newKey); + + return new WriterContext(fullKey, output); + } + + WriterContext extend() { + return new WriterContext(key, output); + } + + void writeKey() { + if (key.isEmpty()) { + return; + } + + if (output.length() > 0) { + output.append('\n'); + } + + if (isArrayOfTable) { + output.append("[[").append(key).append("]]\n"); + } else { + output.append('[').append(key).append("]\n"); + } + } + + void indent() { + output.append(key.isEmpty() ? "" : " "); + } + + WriterContext setIsArrayOfTable(boolean isArrayOfTable) { + this.isArrayOfTable = isArrayOfTable; + return this; + } +} diff --git a/src/test/java/com/moandjiezana/toml/SerializerTest.java b/src/test/java/com/moandjiezana/toml/ValueWriterTest.java similarity index 77% rename from src/test/java/com/moandjiezana/toml/SerializerTest.java rename to src/test/java/com/moandjiezana/toml/ValueWriterTest.java index 2a78d62..8319e66 100644 --- a/src/test/java/com/moandjiezana/toml/SerializerTest.java +++ b/src/test/java/com/moandjiezana/toml/ValueWriterTest.java @@ -8,9 +8,9 @@ import java.util.*; import static org.junit.Assert.assertEquals; -public class SerializerTest { +public class ValueWriterTest { @Test - public void should_serialize_primitive_types() { + public void should_write_primitive_types() { class TestClass { public String aString; int anInt; @@ -31,7 +31,7 @@ public class SerializerTest { o.aDate = new Date(); String theDate = formatDate(o.aDate); - String serialized = Toml.serializeFrom(o); + String output = Toml.write(o); String expected = "aString = \"hello\"\n" + "anInt = 4\n" + "aFloat = 1.23\n" + @@ -39,12 +39,12 @@ public class SerializerTest { "aBoolean = false\n" + "aDate = " + theDate + "\n"; - assertEquals(expected, serialized); + assertEquals(expected, output); } private String formatDate(Date date) { - // Copying the date formatting code from DateSerializer isn't optimal, but - // I can't see any other way to check date serialization - the test gets + // Copying the date formatting code from DateValueWriter isn't optimal, but + // I can't see any other way to check date formatting - the test gets // run in multiple time zones, so we can't just hard-code a time zone. String dateString = new SimpleDateFormat("yyyy-MM-dd'T'HH:m:ss").format(date); Calendar calendar = new GregorianCalendar(); @@ -55,7 +55,7 @@ public class SerializerTest { } @Test - public void should_serialize_nested_map() { + public void should_write_nested_map() { class SubChild { int anInt; } @@ -80,7 +80,7 @@ public class SerializerTest { parent.child.subChild.anInt = 4; parent.aBoolean = true; - String serialized = Toml.serializeFrom(parent); + String output = Toml.write(parent); String expected = "aBoolean = true\n\n" + "[aMap]\n" + " foo = 1\n" + @@ -90,23 +90,23 @@ public class SerializerTest { " anInt = 2\n\n" + "[child.subChild]\n" + " anInt = 4\n"; - assertEquals(expected, serialized); + assertEquals(expected, output); } @Test - public void should_serialize_array_of_primitive() { + public void should_write_array_of_primitive() { class ArrayTest { int[] array = {1, 2, 3}; } ArrayTest arrayTest = new ArrayTest(); - String serialized = Toml.serializeFrom(arrayTest); + String output = Toml.write(arrayTest); String expected = "array = [ 1, 2, 3 ]\n"; - assertEquals(expected, serialized); + assertEquals(expected, output); } @Test - public void should_serialize_array_of_tables() { + public void should_write_array_of_tables() { class Table { int anInt; @@ -120,28 +120,28 @@ public class SerializerTest { Config config = new Config(); config.table = new Table[]{new Table(1), new Table(2)}; - String serialized = Toml.serializeFrom(config); + String output = Toml.write(config); String expected = "[[table]]\n" + " anInt = 1\n\n" + "[[table]]\n" + " anInt = 2\n"; - assertEquals(expected, serialized); + assertEquals(expected, output); } @Test - public void should_serialize_array_of_array() { + public void should_write_array_of_array() { class ArrayTest { int[][] array = {{1, 2, 3}, {4, 5, 6}}; } ArrayTest arrayTest = new ArrayTest(); - String serialized = Toml.serializeFrom(arrayTest); + String output = Toml.write(arrayTest); String expected = "array = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]\n"; - assertEquals(expected, serialized); + assertEquals(expected, output); } @Test - public void should_serialize_list() { + public void should_write_list() { class ListTest { List aList = new LinkedList(); } @@ -149,7 +149,7 @@ public class SerializerTest { o.aList.add(1); o.aList.add(2); - assertEquals("aList = [ 1, 2 ]\n", Toml.serializeFrom(o)); + assertEquals("aList = [ 1, 2 ]\n", Toml.write(o)); } @Test @@ -158,7 +158,7 @@ public class SerializerTest { List aList = new LinkedList(); Float[] anArray = new Float[0]; } - assertEquals("", Toml.serializeFrom(new TestClass())); + assertEquals("", Toml.write(new TestClass())); } @Test @@ -173,11 +173,11 @@ public class SerializerTest { B b = new B(); } - assertEquals("[b.c]\n anInt = 1\n", Toml.serializeFrom(new A())); + assertEquals("[b.c]\n anInt = 1\n", Toml.write(new A())); } @Test - public void should_serialize_nested_arrays_of_tables() { + public void should_write_nested_arrays_of_tables() { class Physical { String color; String shape; @@ -235,12 +235,12 @@ public class SerializerTest { "\n"; - String serialized = Toml.serializeFrom(basket); - assertEquals(expected, serialized); + String output = Toml.write(basket); + assertEquals(expected, output); } @Test - public void should_serialize_classes_with_inheritance() { + public void should_write_classes_with_inheritance() { class Parent { protected int anInt = 2; } @@ -250,23 +250,23 @@ public class SerializerTest { Child child = new Child(); String expected = "aBoolean = true\nanInt = 2\n"; - assertEquals(expected, Toml.serializeFrom(child)); + assertEquals(expected, Toml.write(child)); } @Test - public void should_serialize_empty_toml_to_empty_string() { + public void should_write_empty_toml_to_empty_string() { Toml toml = new Toml(); assertEquals("", toml.serialize()); } @Test - public void should_serialize_strings_to_toml_utf8() throws UnsupportedEncodingException { + public void should_write_strings_to_toml_utf8() throws UnsupportedEncodingException { String input = " é foo € \b \t \n \f \r \" \\ "; - assertEquals("\" \\u00E9 foo \\u20AC \\b \\t \\n \\f \\r \\\" \\ \"", Toml.serializeFrom(input)); + assertEquals("\" \\u00E9 foo \\u20AC \\b \\t \\n \\f \\r \\\" \\ \"", Toml.write(input)); // Check unicode code points greater than 0XFFFF input = " \uD801\uDC28 \uD840\uDC0B "; - assertEquals("\" \\U00010428 \\U0002000B \"", Toml.serializeFrom(input)); + assertEquals("\" \\U00010428 \\U0002000B \"", Toml.write(input)); } @Test @@ -281,11 +281,11 @@ public class SerializerTest { "\"5€\" = 2\n" + "\"c$d\" = 3\n" + "\"e/f\" = 4\n"; - assertEquals(expected, Toml.serializeFrom(aMap)); + assertEquals(expected, Toml.write(aMap)); } @Test - public void should_serialize_from_toml() { + public void should_write_from_toml() { String tomlString = "a = 1\n"; Toml toml = new Toml().parse(tomlString); assertEquals(tomlString, toml.serialize());