Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Serialization-pocalypse: change serialization format

The previous use of Java's default serialization dumped
all implementation-detail class names and fields into the serialization,
making it basically impossible to improve the implementation.

Two strategies here:
 - prohibit serialization of unresolved configs, which are
   the location of a lot of implementation detail
 - delegate all serialization to an Externalizable
   SerializedConfigValue class, which serializes
   using fields that have lengths. Unknown fields
   can thus be skipped and we can write code to
   support obsolete fields, and so on.

As a side effect, this makes the serialization far more compact
because we don't need the Java per-class header noise, and we
jump through some hoops to avoid writing out duplicate ConfigOrigin
information. It still isn't super-compact compared to something
like protobuf but it's a lot less insane.
  • Loading branch information...
commit 388d85fb5d3d8deff0ad0719222ef4d3ac76f6e4 1 parent d14d8ca
@havocp havocp authored
Showing with 992 additions and 499 deletions.
  1. +10 −6 NEWS.md
  2. +0 −2  config/build.sbt
  3. +0 −2  config/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java
  4. +1 −4 config/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java
  5. +10 −2 config/src/main/java/com/typesafe/config/impl/ConfigBoolean.java
  6. +0 −12 config/src/main/java/com/typesafe/config/impl/ConfigConcatenation.java
  7. +0 −18 config/src/main/java/com/typesafe/config/impl/ConfigDelayedMerge.java
  8. +0 −19 config/src/main/java/com/typesafe/config/impl/ConfigDelayedMergeObject.java
  9. +10 −2 config/src/main/java/com/typesafe/config/impl/ConfigDouble.java
  10. +10 −2 config/src/main/java/com/typesafe/config/impl/ConfigInt.java
  11. +10 −2 config/src/main/java/com/typesafe/config/impl/ConfigLong.java
  12. +10 −2 config/src/main/java/com/typesafe/config/impl/ConfigNull.java
  13. +10 −2 config/src/main/java/com/typesafe/config/impl/ConfigNumber.java
  14. +0 −1  config/src/main/java/com/typesafe/config/impl/ConfigReference.java
  15. +10 −2 config/src/main/java/com/typesafe/config/impl/ConfigString.java
  16. +2 −2 config/src/main/java/com/typesafe/config/impl/ConfigSubstitution.java
  17. +1 −0  config/src/main/java/com/typesafe/config/impl/OriginType.java
  18. +1 −4 config/src/main/java/com/typesafe/config/impl/Path.java
  19. +478 −0 config/src/main/java/com/typesafe/config/impl/SerializedConfigValue.java
  20. +6 −0 config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
  21. +5 −9 config/src/main/java/com/typesafe/config/impl/SimpleConfigList.java
  22. +9 −2 config/src/main/java/com/typesafe/config/impl/SimpleConfigObject.java
  23. +172 −4 config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java
  24. +1 −5 config/src/main/java/com/typesafe/config/impl/SubstitutionExpression.java
  25. +2 −157 config/src/test/scala/com/typesafe/config/impl/ConfigSubstitutionTest.scala
  26. +15 −0 config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
  27. +130 −233 config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
  28. +89 −5 config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
View
16 NEWS.md
@@ -1,5 +1,15 @@
# 0.NEXT.0: Sometime
+ - the serialization format has changed to one that's extensible
+ and lets the library evolve without breaking serialization all
+ the time. The new format is also much more compact. However,
+ this change is incompatible with old serializations, if you
+ rely on that. The hope is to avoid serialization breakage in
+ the future now that the format is not the default Java one
+ (which was a direct dump of all the implementation details).
+ - serializing an unresolved Config (one that hasn't had
+ resolve() called on it) is no longer supported, you will get
+ NotSerializableException if you try.
- supports self-referential substitutions, such as
`path=${path}":/bin"`, by "looking backward" to the previous
value of `path`
@@ -32,12 +42,6 @@
ConfigIncludeContext.parseOptions() if appropriate.
- cycles in include statements (self-includes) are now detected
and result in a nicer error instead of stack overflow
- - the serialization format has changed for a Config that has not
- had resolve() called on it. The library can still deserialize
- the old format, but old versions of the library will not be
- able to deserialize the new format. Serializing unresolved
- Config is probably a bad idea anyway and maybe shouldn't even
- be supported, but keeping it for back compat.
- since 0.3.0, there is an obscure incompatible semantic change
in that self-referential substitutions where the cycle could
be broken by partially resolving the object now "look backward"
View
2  config/build.sbt
@@ -18,8 +18,6 @@ libraryDependencies += "net.liftweb" %% "lift-json" % "2.4" % "test"
libraryDependencies += "com.novocode" % "junit-interface" % "0.7" % "test"
-libraryDependencies += "commons-codec" % "commons-codec" % "1.4" % "test"
-
externalResolvers += "Scala Tools Snapshots" at "http://scala-tools.org/repo-snapshots/"
seq(findbugsSettings : _*)
View
2  config/src/main/java/com/typesafe/config/impl/AbstractConfigObject.java
@@ -18,8 +18,6 @@
abstract class AbstractConfigObject extends AbstractConfigValue implements ConfigObject {
- private static final long serialVersionUID = 1L;
-
final private SimpleConfig config;
protected AbstractConfigObject(ConfigOrigin origin) {
View
5 config/src/main/java/com/typesafe/config/impl/AbstractConfigValue.java
@@ -3,7 +3,6 @@
*/
package com.typesafe.config.impl;
-import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -21,9 +20,7 @@
* improperly-factored and non-modular code. Please don't add parent().
*
*/
-abstract class AbstractConfigValue implements ConfigValue, MergeableValue, Serializable {
-
- private static final long serialVersionUID = 1L;
+abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
final private SimpleConfigOrigin origin;
View
12 config/src/main/java/com/typesafe/config/impl/ConfigBoolean.java
@@ -3,12 +3,15 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValueType;
-final class ConfigBoolean extends AbstractConfigValue {
+final class ConfigBoolean extends AbstractConfigValue implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
final private boolean value;
@@ -36,4 +39,9 @@ String transformToString() {
protected ConfigBoolean newCopy(ConfigOrigin origin) {
return new ConfigBoolean(origin, value);
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
12 config/src/main/java/com/typesafe/config/impl/ConfigConcatenation.java
@@ -1,6 +1,5 @@
package com.typesafe.config.impl;
-import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -23,7 +22,6 @@
* since a concat of objects really will merge, not concatenate.
*/
final class ConfigConcatenation extends AbstractConfigValue implements Unmergeable {
- private static final long serialVersionUID = 1L;
final private List<AbstractConfigValue> pieces;
@@ -234,16 +232,6 @@ protected void render(StringBuilder sb, int indent, boolean formatted) {
}
}
- // This ridiculous hack is because some JDK versions apparently can't
- // serialize an array, which is used to implement ArrayList and EmptyList.
- // maybe
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627
- private Object writeReplace() throws ObjectStreamException {
- // switch to LinkedList
- return new ConfigConcatenation(origin(), new java.util.LinkedList<AbstractConfigValue>(
- pieces));
- }
-
static List<AbstractConfigValue> valuesFromPieces(ConfigOrigin origin, List<Object> pieces) {
List<AbstractConfigValue> values = new ArrayList<AbstractConfigValue>(pieces.size());
for (Object p : pieces) {
View
18 config/src/main/java/com/typesafe/config/impl/ConfigDelayedMerge.java
@@ -3,7 +3,6 @@
*/
package com.typesafe.config.impl;
-import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -24,15 +23,8 @@
final class ConfigDelayedMerge extends AbstractConfigValue implements Unmergeable,
ReplaceableMergeStack {
- private static final long serialVersionUID = 1L;
-
// earlier items in the stack win
final private List<AbstractConfigValue> stack;
- // this is just here for serialization compat; whether we ignore is purely
- // a function of the bottom of the merge stack
- @SuppressWarnings("unused")
- @Deprecated
- final private boolean ignoresFallbacks = false;
ConfigDelayedMerge(ConfigOrigin origin, List<AbstractConfigValue> stack) {
super(origin);
@@ -283,14 +275,4 @@ static void render(List<AbstractConfigValue> stack, StringBuilder sb, int indent
sb.append("# ) end of unresolved merge\n");
}
}
-
- // This ridiculous hack is because some JDK versions apparently can't
- // serialize an array, which is used to implement ArrayList and EmptyList.
- // maybe
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627
- private Object writeReplace() throws ObjectStreamException {
- // switch to LinkedList
- return new ConfigDelayedMerge(origin(),
- new java.util.LinkedList<AbstractConfigValue>(stack));
- }
}
View
19 config/src/main/java/com/typesafe/config/impl/ConfigDelayedMergeObject.java
@@ -3,7 +3,6 @@
*/
package com.typesafe.config.impl;
-import java.io.ObjectStreamException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -21,16 +20,8 @@
final class ConfigDelayedMergeObject extends AbstractConfigObject implements Unmergeable,
ReplaceableMergeStack {
- private static final long serialVersionUID = 1L;
-
final private List<AbstractConfigValue> stack;
- // this is just here for serialization compat; whether we ignore is purely
- // a function of the bottom of the merge stack
- @SuppressWarnings("unused")
- @Deprecated
- final private boolean ignoresFallbacks = false;
-
ConfigDelayedMergeObject(ConfigOrigin origin, List<AbstractConfigValue> stack) {
super(origin);
this.stack = stack;
@@ -317,14 +308,4 @@ protected AbstractConfigValue attemptPeekWithPartialResolve(String key) {
"Delayed merge stack does not contain any unmergeable values");
}
-
- // This ridiculous hack is because some JDK versions apparently can't
- // serialize an array, which is used to implement ArrayList and EmptyList.
- // maybe
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627
- private Object writeReplace() throws ObjectStreamException {
- // switch to LinkedList
- return new ConfigDelayedMergeObject(origin(),
- new java.util.LinkedList<AbstractConfigValue>(stack));
- }
}
View
12 config/src/main/java/com/typesafe/config/impl/ConfigDouble.java
@@ -3,12 +3,15 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValueType;
-final class ConfigDouble extends ConfigNumber {
+final class ConfigDouble extends ConfigNumber implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
final private double value;
@@ -50,4 +53,9 @@ protected double doubleValue() {
protected ConfigDouble newCopy(ConfigOrigin origin) {
return new ConfigDouble(origin, value, originalText);
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
12 config/src/main/java/com/typesafe/config/impl/ConfigInt.java
@@ -3,12 +3,15 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValueType;
-final class ConfigInt extends ConfigNumber {
+final class ConfigInt extends ConfigNumber implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
final private int value;
@@ -50,4 +53,9 @@ protected double doubleValue() {
protected ConfigInt newCopy(ConfigOrigin origin) {
return new ConfigInt(origin, value, originalText);
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
12 config/src/main/java/com/typesafe/config/impl/ConfigLong.java
@@ -3,12 +3,15 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValueType;
-final class ConfigLong extends ConfigNumber {
+final class ConfigLong extends ConfigNumber implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
final private long value;
@@ -50,4 +53,9 @@ protected double doubleValue() {
protected ConfigLong newCopy(ConfigOrigin origin) {
return new ConfigLong(origin, value, originalText);
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
12 config/src/main/java/com/typesafe/config/impl/ConfigNull.java
@@ -3,6 +3,9 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValueType;
@@ -14,9 +17,9 @@
* not.
*
*/
-final class ConfigNull extends AbstractConfigValue {
+final class ConfigNull extends AbstractConfigValue implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
ConfigNull(ConfigOrigin origin) {
super(origin);
@@ -46,4 +49,9 @@ protected void render(StringBuilder sb, int indent, boolean formatted) {
protected ConfigNull newCopy(ConfigOrigin origin) {
return new ConfigNull(origin);
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
12 config/src/main/java/com/typesafe/config/impl/ConfigNumber.java
@@ -3,12 +3,15 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigOrigin;
-abstract class ConfigNumber extends AbstractConfigValue {
+abstract class ConfigNumber extends AbstractConfigValue implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
// This is so when we concatenate a number into a string (say it appears in
// a sentence) we always have it exactly as the person typed it into the
@@ -99,4 +102,9 @@ static ConfigNumber newNumber(ConfigOrigin origin, double number,
return new ConfigDouble(origin, number, originalText);
}
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
1  config/src/main/java/com/typesafe/config/impl/ConfigReference.java
@@ -13,7 +13,6 @@
* kind of value.
*/
final class ConfigReference extends AbstractConfigValue implements Unmergeable {
- private static final long serialVersionUID = 1L;
final private SubstitutionExpression expr;
// the length of any prefixes added with relativized()
View
12 config/src/main/java/com/typesafe/config/impl/ConfigString.java
@@ -3,12 +3,15 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValueType;
-final class ConfigString extends AbstractConfigValue {
+final class ConfigString extends AbstractConfigValue implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
final private String value;
@@ -41,4 +44,9 @@ protected void render(StringBuilder sb, int indent, boolean formatted) {
protected ConfigString newCopy(ConfigOrigin origin) {
return new ConfigString(origin, value);
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
4 config/src/main/java/com/typesafe/config/impl/ConfigSubstitution.java
@@ -5,6 +5,7 @@
import java.io.IOException;
import java.io.ObjectStreamException;
+import java.io.Serializable;
import java.util.Collection;
import java.util.List;
@@ -18,8 +19,7 @@
* and ConfigConcatenation.
*/
@Deprecated
-final class ConfigSubstitution extends AbstractConfigValue implements
- Unmergeable {
+final class ConfigSubstitution extends AbstractConfigValue implements Unmergeable, Serializable {
private static final long serialVersionUID = 1L;
View
1  config/src/main/java/com/typesafe/config/impl/OriginType.java
@@ -1,5 +1,6 @@
package com.typesafe.config.impl;
+// caution: ordinals used in serialization
enum OriginType {
GENERIC,
FILE,
View
5 config/src/main/java/com/typesafe/config/impl/Path.java
@@ -3,15 +3,12 @@
*/
package com.typesafe.config.impl;
-import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import com.typesafe.config.ConfigException;
-final class Path implements Serializable {
-
- private static final long serialVersionUID = 1L;
+final class Path {
final private String first;
final private Path remainder;
View
478 config/src/main/java/com/typesafe/config/impl/SerializedConfigValue.java
@@ -0,0 +1,478 @@
+/**
+ * Copyright (C) 2011-2012 Typesafe Inc. <http://typesafe.com>
+ */
+package com.typesafe.config.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectStreamException;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigException;
+import com.typesafe.config.ConfigList;
+import com.typesafe.config.ConfigObject;
+import com.typesafe.config.ConfigOrigin;
+import com.typesafe.config.ConfigValue;
+import com.typesafe.config.ConfigValueType;
+
+/**
+ * Deliberately shoving all the serialization code into this class instead of
+ * doing it OO-style with each subclass. Seems better to have it all in one
+ * place. This class implements a lame serialization format that supports
+ * skipping unknown fields, so it's moderately more extensible than the default
+ * Java serialization format.
+ */
+class SerializedConfigValue extends AbstractConfigValue implements Externalizable {
+
+ // this is the version used by Java serialization, if it increments it's
+ // essentially an ABI break and bad
+ private static final long serialVersionUID = 1L;
+
+ // this is how we try to be extensible
+ static enum SerializedField {
+ // represents a field code we didn't recognize
+ UNKNOWN,
+
+ // end of a list of fields
+ END_MARKER,
+
+ // Fields at the root
+ ROOT_VALUE,
+ ROOT_WAS_CONFIG,
+
+ // Fields that make up a value
+ VALUE_DATA,
+ VALUE_ORIGIN,
+
+ // Fields that make up an origin
+ ORIGIN_DESCRIPTION,
+ ORIGIN_LINE_NUMBER,
+ ORIGIN_END_LINE_NUMBER,
+ ORIGIN_TYPE,
+ ORIGIN_URL,
+ ORIGIN_COMMENTS,
+ ORIGIN_NULL_DESCRIPTION,
+ ORIGIN_NULL_URL,
+ ORIGIN_NULL_COMMENTS;
+
+ static SerializedField forInt(int b) {
+ if (b < values().length)
+ return values()[b];
+ else
+ return UNKNOWN;
+ }
+ };
+
+ private static enum SerializedValueType {
+ // the ordinals here are in the wire format, caution
+ NULL(ConfigValueType.NULL),
+ BOOLEAN(ConfigValueType.BOOLEAN),
+ INT(ConfigValueType.NUMBER),
+ LONG(ConfigValueType.NUMBER),
+ DOUBLE(ConfigValueType.NUMBER),
+ STRING(ConfigValueType.STRING),
+ LIST(ConfigValueType.LIST),
+ OBJECT(ConfigValueType.OBJECT);
+
+ ConfigValueType configType;
+
+ SerializedValueType(ConfigValueType configType) {
+ this.configType = configType;
+ }
+
+ static SerializedValueType forInt(int b) {
+ if (b < values().length)
+ return values()[b];
+ else
+ return null;
+ }
+
+ static SerializedValueType forValue(ConfigValue value) {
+ ConfigValueType t = value.valueType();
+ if (t == ConfigValueType.NUMBER) {
+ if (value instanceof ConfigInt)
+ return INT;
+ else if (value instanceof ConfigLong)
+ return LONG;
+ else if (value instanceof ConfigDouble)
+ return DOUBLE;
+ } else {
+ for (SerializedValueType st : values()) {
+ if (st.configType == t)
+ return st;
+ }
+ }
+
+ throw new ConfigException.BugOrBroken("don't know how to serialize " + value);
+ }
+ };
+
+ private ConfigValue value;
+ private boolean wasConfig;
+
+ // this has to be public for the Java deserializer
+ public SerializedConfigValue() {
+ super(null);
+ }
+
+ SerializedConfigValue(ConfigValue value) {
+ this();
+ this.value = value;
+ this.wasConfig = false;
+ }
+
+ SerializedConfigValue(Config conf) {
+ this(conf.root());
+ this.wasConfig = true;
+ }
+
+ // when Java deserializer reads this object, return the contained
+ // object instead.
+ private Object readResolve() throws ObjectStreamException {
+ if (wasConfig)
+ return ((ConfigObject) value).toConfig();
+ else
+ return value;
+ }
+
+ private static class FieldOut {
+ final SerializedField code;
+ final ByteArrayOutputStream bytes;
+ final DataOutput data;
+
+ FieldOut(SerializedField code) {
+ this.code = code;
+ this.bytes = new ByteArrayOutputStream();
+ this.data = new DataOutputStream(bytes);
+ }
+ }
+
+ // this is a separate function to prevent bugs writing to the
+ // outer stream instead of field.data
+ private static void writeOriginField(DataOutput out, SerializedField code, Object v)
+ throws IOException {
+ switch (code) {
+ case ORIGIN_DESCRIPTION:
+ out.writeUTF((String) v);
+ break;
+ case ORIGIN_LINE_NUMBER:
+ out.writeInt((Integer) v);
+ break;
+ case ORIGIN_END_LINE_NUMBER:
+ out.writeInt((Integer) v);
+ break;
+ case ORIGIN_TYPE:
+ out.writeByte((Integer) v);
+ break;
+ case ORIGIN_URL:
+ out.writeUTF((String) v);
+ break;
+ case ORIGIN_COMMENTS:
+ @SuppressWarnings("unchecked")
+ List<String> list = (List<String>) v;
+ int size = list.size();
+ out.writeInt(size);
+ for (String s : list) {
+ out.writeUTF(s);
+ }
+ break;
+ case ORIGIN_NULL_DESCRIPTION: // FALL THRU
+ case ORIGIN_NULL_URL: // FALL THRU
+ case ORIGIN_NULL_COMMENTS:
+ // nothing to write out besides code and length
+ break;
+ default:
+ throw new IOException("Unhandled field from origin: " + code);
+ }
+ }
+
+ private static void writeOrigin(DataOutput out, SimpleConfigOrigin origin,
+ SimpleConfigOrigin baseOrigin) throws IOException {
+ Map<SerializedField, Object> m = origin.toFieldsDelta(baseOrigin);
+ for (Map.Entry<SerializedField, Object> e : m.entrySet()) {
+ FieldOut field = new FieldOut(e.getKey());
+ Object v = e.getValue();
+ writeOriginField(field.data, field.code, v);
+ writeField(out, field);
+ }
+ writeEndMarker(out);
+ }
+
+ private static SimpleConfigOrigin readOrigin(DataInput in, SimpleConfigOrigin baseOrigin)
+ throws IOException {
+ Map<SerializedField, Object> m = new EnumMap<SerializedField, Object>(SerializedField.class);
+ while (true) {
+ Object v = null;
+ SerializedField field = readCode(in);
+ switch (field) {
+ case END_MARKER:
+ return SimpleConfigOrigin.fromBase(baseOrigin, m);
+ case ORIGIN_DESCRIPTION:
+ in.readInt(); // discard length
+ v = in.readUTF();
+ break;
+ case ORIGIN_LINE_NUMBER:
+ in.readInt(); // discard length
+ v = in.readInt();
+ break;
+ case ORIGIN_END_LINE_NUMBER:
+ in.readInt(); // discard length
+ v = in.readInt();
+ break;
+ case ORIGIN_TYPE:
+ in.readInt(); // discard length
+ v = in.readUnsignedByte();
+ break;
+ case ORIGIN_URL:
+ in.readInt(); // discard length
+ v = in.readUTF();
+ break;
+ case ORIGIN_COMMENTS:
+ in.readInt(); // discard length
+ int size = in.readInt();
+ List<String> list = new ArrayList<String>(size);
+ for (int i = 0; i < size; ++i) {
+ list.add(in.readUTF());
+ }
+ v = list;
+ break;
+ case ORIGIN_NULL_DESCRIPTION: // FALL THRU
+ case ORIGIN_NULL_URL: // FALL THRU
+ case ORIGIN_NULL_COMMENTS:
+ // nothing to read besides code and length
+ in.readInt(); // discard length
+ v = ""; // just something non-null to put in the map
+ break;
+ case ROOT_VALUE:
+ case ROOT_WAS_CONFIG:
+ case VALUE_DATA:
+ case VALUE_ORIGIN:
+ throw new IOException("Not expecting this field here: " + field);
+ case UNKNOWN:
+ // skip unknown field
+ skipField(in);
+ break;
+ }
+ if (v != null)
+ m.put(field, v);
+ }
+ }
+
+ private static void writeValueData(DataOutput out, ConfigValue value) throws IOException {
+ SerializedValueType st = SerializedValueType.forValue(value);
+ out.writeByte(st.ordinal());
+ switch (st) {
+ case BOOLEAN:
+ out.writeBoolean(((ConfigBoolean) value).unwrapped());
+ break;
+ case NULL:
+ break;
+ case INT:
+ // saving numbers as both string and binary is redundant but easy
+ out.writeInt(((ConfigInt) value).unwrapped());
+ out.writeUTF(((ConfigNumber) value).transformToString());
+ break;
+ case LONG:
+ out.writeLong(((ConfigLong) value).unwrapped());
+ out.writeUTF(((ConfigNumber) value).transformToString());
+ break;
+ case DOUBLE:
+ out.writeDouble(((ConfigDouble) value).unwrapped());
+ out.writeUTF(((ConfigNumber) value).transformToString());
+ break;
+ case STRING:
+ out.writeUTF(((ConfigString) value).unwrapped());
+ break;
+ case LIST:
+ ConfigList list = (ConfigList) value;
+ out.writeInt(list.size());
+ for (ConfigValue v : list) {
+ writeValue(out, v, (SimpleConfigOrigin) list.origin());
+ }
+ break;
+ case OBJECT:
+ ConfigObject obj = (ConfigObject) value;
+ out.writeInt(obj.size());
+ for (Map.Entry<String, ConfigValue> e : obj.entrySet()) {
+ out.writeUTF(e.getKey());
+ writeValue(out, e.getValue(), (SimpleConfigOrigin) obj.origin());
+ }
+ break;
+ }
+ }
+
+ private static AbstractConfigValue readValueData(DataInput in, SimpleConfigOrigin origin)
+ throws IOException {
+ int stb = in.readUnsignedByte();
+ SerializedValueType st = SerializedValueType.forInt(stb);
+ if (st == null)
+ throw new IOException("Unknown serialized value type: " + stb);
+ switch (st) {
+ case BOOLEAN:
+ return new ConfigBoolean(origin, in.readBoolean());
+ case NULL:
+ return new ConfigNull(origin);
+ case INT:
+ int vi = in.readInt();
+ String si = in.readUTF();
+ return new ConfigInt(origin, vi, si);
+ case LONG:
+ long vl = in.readLong();
+ String sl = in.readUTF();
+ return new ConfigLong(origin, vl, sl);
+ case DOUBLE:
+ double vd = in.readDouble();
+ String sd = in.readUTF();
+ return new ConfigDouble(origin, vd, sd);
+ case STRING:
+ return new ConfigString(origin, in.readUTF());
+ case LIST:
+ int listSize = in.readInt();
+ List<AbstractConfigValue> list = new ArrayList<AbstractConfigValue>(listSize);
+ for (int i = 0; i < listSize; ++i) {
+ AbstractConfigValue v = readValue(in, origin);
+ list.add(v);
+ }
+ return new SimpleConfigList(origin, list);
+ case OBJECT:
+ int mapSize = in.readInt();
+ Map<String, AbstractConfigValue> map = new HashMap<String, AbstractConfigValue>(mapSize);
+ for (int i = 0; i < mapSize; ++i) {
+ String key = in.readUTF();
+ AbstractConfigValue v = readValue(in, origin);
+ map.put(key, v);
+ }
+ return new SimpleConfigObject(origin, map);
+ }
+ throw new IOException("Unhandled serialized value type: " + st);
+ }
+
+ private static void writeValue(DataOutput out, ConfigValue value, SimpleConfigOrigin baseOrigin)
+ throws IOException {
+ FieldOut origin = new FieldOut(SerializedField.VALUE_ORIGIN);
+ writeOrigin(origin.data, (SimpleConfigOrigin) value.origin(),
+ baseOrigin);
+ writeField(out, origin);
+
+ FieldOut data = new FieldOut(SerializedField.VALUE_DATA);
+ writeValueData(data.data, value);
+ writeField(out, data);
+
+ writeEndMarker(out);
+ }
+
+ private static AbstractConfigValue readValue(DataInput in, SimpleConfigOrigin baseOrigin)
+ throws IOException {
+ AbstractConfigValue value = null;
+ SimpleConfigOrigin origin = null;
+ while (true) {
+ SerializedField code = readCode(in);
+ if (code == SerializedField.END_MARKER) {
+ if (value == null)
+ throw new IOException("No value data found in serialization of value");
+ return value;
+ } else if (code == SerializedField.VALUE_DATA) {
+ if (origin == null)
+ throw new IOException("Origin must be stored before value data");
+ in.readInt(); // discard length
+ value = readValueData(in, origin);
+ } else if (code == SerializedField.VALUE_ORIGIN) {
+ in.readInt(); // discard length
+ origin = readOrigin(in, baseOrigin);
+ } else {
+ // ignore unknown field
+ skipField(in);
+ }
+ }
+ }
+
+ private static void writeField(DataOutput out, FieldOut field) throws IOException {
+ byte[] bytes = field.bytes.toByteArray();
+ out.writeByte(field.code.ordinal());
+ out.writeInt(bytes.length);
+ out.write(bytes);
+ }
+
+ private static void writeEndMarker(DataOutput out) throws IOException {
+ out.writeByte(SerializedField.END_MARKER.ordinal());
+ }
+
+ private static SerializedField readCode(DataInput in) throws IOException {
+ int c = in.readUnsignedByte();
+ if (c == SerializedField.UNKNOWN.ordinal())
+ throw new IOException("field code " + c + " is not supposed to be on the wire");
+ return SerializedField.forInt(c);
+ }
+
+ private static void skipField(DataInput in) throws IOException {
+ int len = in.readInt();
+ in.skipBytes(len);
+ }
+
+ @Override
+ public void writeExternal(ObjectOutput out) throws IOException {
+ if (((AbstractConfigValue) value).resolveStatus() != ResolveStatus.RESOLVED)
+ throw new NotSerializableException(
+ "tried to serialize a value with unresolved substitutions, need to Config#resolve() first, see API docs");
+ FieldOut field = new FieldOut(SerializedField.ROOT_VALUE);
+ writeValue(field.data, value, null /* baseOrigin */);
+ writeField(out, field);
+
+ field = new FieldOut(SerializedField.ROOT_WAS_CONFIG);
+ field.data.writeBoolean(wasConfig);
+ writeField(out, field);
+
+ writeEndMarker(out);
+ }
+
+ @Override
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ while (true) {
+ SerializedField code = readCode(in);
+ if (code == SerializedField.END_MARKER) {
+ return;
+ } else if (code == SerializedField.ROOT_VALUE) {
+ in.readInt(); // discard length
+ this.value = readValue(in, null /* baseOrigin */);
+ } else if (code == SerializedField.ROOT_WAS_CONFIG) {
+ in.readInt(); // discard length
+ this.wasConfig = in.readBoolean();
+ } else {
+ // ignore unknown field
+ skipField(in);
+ }
+ }
+ }
+
+ private static ConfigException shouldNotBeUsed() {
+ return new ConfigException.BugOrBroken(SerializedConfigValue.class.getName()
+ + " should not exist outside of serialization");
+ }
+
+ @Override
+ public ConfigValueType valueType() {
+ throw shouldNotBeUsed();
+ }
+
+ @Override
+ public Object unwrapped() {
+ throw shouldNotBeUsed();
+ }
+
+ @Override
+ protected SerializedConfigValue newCopy(ConfigOrigin origin) {
+ throw shouldNotBeUsed();
+ }
+}
View
6 config/src/main/java/com/typesafe/config/impl/SimpleConfig.java
@@ -3,6 +3,7 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.ArrayList;
@@ -844,4 +845,9 @@ public SimpleConfig withoutPath(String pathExpression) {
Path path = Path.newPath(pathExpression);
return new SimpleConfig(root().withoutPath(path));
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
14 config/src/main/java/com/typesafe/config/impl/SimpleConfigList.java
@@ -4,6 +4,7 @@
package com.typesafe.config.impl;
import java.io.ObjectStreamException;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -16,9 +17,9 @@
import com.typesafe.config.ConfigValue;
import com.typesafe.config.ConfigValueType;
-final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
+final class SimpleConfigList extends AbstractConfigValue implements ConfigList, Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
final private List<AbstractConfigValue> value;
final private boolean resolved;
@@ -409,13 +410,8 @@ final SimpleConfigList concatenate(SimpleConfigList other) {
return new SimpleConfigList(combinedOrigin, combined);
}
- // This ridiculous hack is because some JDK versions apparently can't
- // serialize an array, which is used to implement ArrayList and EmptyList.
- // maybe
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627
+ // serialization all goes through SerializedConfigValue
private Object writeReplace() throws ObjectStreamException {
- // switch to LinkedList
- return new SimpleConfigList(origin(), new java.util.LinkedList<AbstractConfigValue>(value),
- resolveStatus());
+ return new SerializedConfigValue(this);
}
}
View
11 config/src/main/java/com/typesafe/config/impl/SimpleConfigObject.java
@@ -3,6 +3,8 @@
*/
package com.typesafe.config.impl;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
@@ -18,9 +20,9 @@
import com.typesafe.config.ConfigOrigin;
import com.typesafe.config.ConfigValue;
-final class SimpleConfigObject extends AbstractConfigObject {
+final class SimpleConfigObject extends AbstractConfigObject implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
// this map should never be modified - assume immutable
final private Map<String, AbstractConfigValue> value;
@@ -484,4 +486,9 @@ final static SimpleConfigObject emptyMissing(ConfigOrigin baseOrigin) {
baseOrigin.description() + " (not found)"),
Collections.<String, AbstractConfigValue> emptyMap());
}
+
+ // serialization all goes through SerializedConfigValue
+ private Object writeReplace() throws ObjectStreamException {
+ return new SerializedConfigValue(this);
+ }
}
View
176 config/src/main/java/com/typesafe/config/impl/SimpleConfigOrigin.java
@@ -4,23 +4,24 @@
package com.typesafe.config.impl;
import java.io.File;
-import java.io.Serializable;
+import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.EnumMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigOrigin;
+import com.typesafe.config.impl.SerializedConfigValue.SerializedField;
// it would be cleaner to have a class hierarchy for various origin types,
// but was hoping this would be enough simpler to be a little messy. eh.
-final class SimpleConfigOrigin implements ConfigOrigin, Serializable {
-
- private static final long serialVersionUID = 1L;
+final class SimpleConfigOrigin implements ConfigOrigin {
final private String description;
final private int lineNumber;
@@ -349,4 +350,171 @@ static ConfigOrigin mergeOrigins(Collection<? extends ConfigOrigin> stack) {
return mergeOrigins(remaining);
}
}
+
+ Map<SerializedField, Object> toFields() {
+ Map<SerializedField, Object> m = new EnumMap<SerializedField, Object>(SerializedField.class);
+
+ if (description != null)
+ m.put(SerializedField.ORIGIN_DESCRIPTION, description);
+
+ if (lineNumber >= 0)
+ m.put(SerializedField.ORIGIN_LINE_NUMBER, lineNumber);
+ if (endLineNumber >= 0)
+ m.put(SerializedField.ORIGIN_END_LINE_NUMBER, endLineNumber);
+
+ m.put(SerializedField.ORIGIN_TYPE, originType.ordinal());
+
+ if (urlOrNull != null)
+ m.put(SerializedField.ORIGIN_URL, urlOrNull);
+ if (commentsOrNull != null)
+ m.put(SerializedField.ORIGIN_COMMENTS, commentsOrNull);
+
+ return m;
+ }
+
+ Map<SerializedField, Object> toFieldsDelta(SimpleConfigOrigin baseOrigin) {
+ Map<SerializedField, Object> baseFields;
+ if (baseOrigin != null)
+ baseFields = baseOrigin.toFields();
+ else
+ baseFields = Collections.<SerializedField, Object> emptyMap();
+ return fieldsDelta(baseFields, toFields());
+ }
+
+ // Here we're trying to avoid serializing the same info over and over
+ // in the common case that child objects have the same origin fields
+ // as their parent objects. e.g. we don't need to store the source
+ // filename with every single value.
+ static Map<SerializedField, Object> fieldsDelta(Map<SerializedField, Object> base,
+ Map<SerializedField, Object> child) {
+ Map<SerializedField, Object> m = new EnumMap<SerializedField, Object>(child);
+
+ for (Map.Entry<SerializedField, Object> baseEntry : base.entrySet()) {
+ SerializedField f = baseEntry.getKey();
+ if (m.containsKey(f)
+ && ConfigImplUtil.equalsHandlingNull(baseEntry.getValue(), m.get(f))) {
+ // if field is unchanged, just remove it so we inherit
+ m.remove(f);
+ } else if (!m.containsKey(f)) {
+ // if field has been removed, we have to add a deletion entry
+ switch (f) {
+ case ORIGIN_DESCRIPTION:
+ m.put(SerializedField.ORIGIN_NULL_DESCRIPTION, "");
+ break;
+ case ORIGIN_LINE_NUMBER:
+ m.put(SerializedField.ORIGIN_LINE_NUMBER, -1);
+ break;
+ case ORIGIN_END_LINE_NUMBER:
+ m.put(SerializedField.ORIGIN_END_LINE_NUMBER, -1);
+ break;
+ case ORIGIN_TYPE:
+ throw new ConfigException.BugOrBroken("should always be an ORIGIN_TYPE field");
+ case ORIGIN_URL:
+ m.put(SerializedField.ORIGIN_NULL_URL, "");
+ break;
+ case ORIGIN_COMMENTS:
+ m.put(SerializedField.ORIGIN_NULL_COMMENTS, "");
+ break;
+ case ORIGIN_NULL_DESCRIPTION: // FALL THRU
+ case ORIGIN_NULL_URL: // FALL THRU
+ case ORIGIN_NULL_COMMENTS:
+ // inherit the deletion, nothing to do
+ break;
+ case END_MARKER:
+ case ROOT_VALUE:
+ case ROOT_WAS_CONFIG:
+ case UNKNOWN:
+ case VALUE_DATA:
+ case VALUE_ORIGIN:
+ throw new ConfigException.BugOrBroken("should not appear here: " + f);
+ }
+ }
+ }
+
+ return m;
+ }
+
+ static SimpleConfigOrigin fromFields(Map<SerializedField, Object> m) throws IOException {
+ String description = (String) m.get(SerializedField.ORIGIN_DESCRIPTION);
+ Integer lineNumber = (Integer) m.get(SerializedField.ORIGIN_LINE_NUMBER);
+ Integer endLineNumber = (Integer) m.get(SerializedField.ORIGIN_END_LINE_NUMBER);
+ Number originTypeOrdinal = (Number) m.get(SerializedField.ORIGIN_TYPE);
+ if (originTypeOrdinal == null)
+ throw new IOException("Missing ORIGIN_TYPE field");
+ OriginType originType = OriginType.values()[originTypeOrdinal.byteValue()];
+ String urlOrNull = (String) m.get(SerializedField.ORIGIN_URL);
+ @SuppressWarnings("unchecked")
+ List<String> commentsOrNull = (List<String>) m.get(SerializedField.ORIGIN_COMMENTS);
+ return new SimpleConfigOrigin(description, lineNumber != null ? lineNumber : -1,
+ endLineNumber != null ? endLineNumber : -1, originType, urlOrNull, commentsOrNull);
+ }
+
+ static Map<SerializedField, Object> applyFieldsDelta(Map<SerializedField, Object> base,
+ Map<SerializedField, Object> delta) throws IOException {
+
+ Map<SerializedField, Object> m = new EnumMap<SerializedField, Object>(delta);
+
+ for (Map.Entry<SerializedField, Object> baseEntry : base.entrySet()) {
+ SerializedField f = baseEntry.getKey();
+ if (delta.containsKey(f)) {
+ // delta overrides when keys are in both
+ // "m" should already contain the right thing
+ } else if (!delta.containsKey(f)) {
+ // base has the key and delta does not.
+ // we inherit from base unless a "NULL" key blocks.
+ switch (f) {
+ case ORIGIN_DESCRIPTION:
+ // add to assembled unless delta nulls
+ if (!delta.containsKey(SerializedField.ORIGIN_NULL_DESCRIPTION))
+ m.put(f, base.get(f));
+ break;
+ case ORIGIN_URL:
+ if (!delta.containsKey(SerializedField.ORIGIN_NULL_URL))
+ m.put(f, base.get(f));
+ break;
+ case ORIGIN_COMMENTS:
+ if (!delta.containsKey(SerializedField.ORIGIN_NULL_COMMENTS))
+ m.put(f, base.get(f));
+ break;
+ case ORIGIN_NULL_DESCRIPTION:
+ if (!delta.containsKey(SerializedField.ORIGIN_DESCRIPTION))
+ m.put(f, base.get(f));
+ break;
+ case ORIGIN_NULL_URL:
+ if (!delta.containsKey(SerializedField.ORIGIN_URL))
+ m.put(f, base.get(f));
+ break;
+ case ORIGIN_NULL_COMMENTS:
+ if (!delta.containsKey(SerializedField.ORIGIN_COMMENTS))
+ m.put(f, base.get(f));
+ break;
+ case ORIGIN_END_LINE_NUMBER: // FALL THRU
+ case ORIGIN_LINE_NUMBER: // FALL THRU
+ case ORIGIN_TYPE:
+ m.put(f, base.get(f));
+ break;
+
+ case END_MARKER:
+ case ROOT_VALUE:
+ case ROOT_WAS_CONFIG:
+ case UNKNOWN:
+ case VALUE_DATA:
+ case VALUE_ORIGIN:
+ throw new ConfigException.BugOrBroken("should not appear here: " + f);
+ }
+ }
+ }
+ return m;
+ }
+
+ static SimpleConfigOrigin fromBase(SimpleConfigOrigin baseOrigin,
+ Map<SerializedField, Object> delta) throws IOException {
+ Map<SerializedField, Object> baseFields;
+ if (baseOrigin != null)
+ baseFields = baseOrigin.toFields();
+ else
+ baseFields = Collections.<SerializedField, Object> emptyMap();
+ Map<SerializedField, Object> fields = applyFieldsDelta(baseFields, delta);
+ return fromFields(fields);
+ }
}
View
6 config/src/main/java/com/typesafe/config/impl/SubstitutionExpression.java
@@ -1,10 +1,6 @@
package com.typesafe.config.impl;
-import java.io.Serializable;
-
-final class SubstitutionExpression implements Serializable {
-
- private static final long serialVersionUID = 1L;
+final class SubstitutionExpression {
final private Path path;
final private boolean optional;
View
159 config/src/test/scala/com/typesafe/config/impl/ConfigSubstitutionTest.scala
@@ -708,163 +708,8 @@ class ConfigSubstitutionTest extends TestUtils {
}
@Test
- def deserializeOldUnresolvedObject() {
- val expectedSerialization = "" +
- "aced00057372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c6543" +
- "6f6e6669674f626a65637400000000000000010200035a001069676e6f72657346616c6c6261636b" +
- "735a00087265736f6c7665644c000576616c756574000f4c6a6176612f7574696c2f4d61703b7872" +
- "002d636f6d2e74797065736166652e636f6e6669672e696d706c2e4162737472616374436f6e6669" +
- "674f626a65637400000000000000010200014c0006636f6e6669677400274c636f6d2f7479706573" +
- "6166652f636f6e6669672f696d706c2f53696d706c65436f6e6669673b7872002c636f6d2e747970" +
- "65736166652e636f6e6669672e696d706c2e4162737472616374436f6e66696756616c7565000000" +
- "00000000010200014c00066f726967696e74002d4c636f6d2f74797065736166652f636f6e666967" +
- "2f696d706c2f53696d706c65436f6e6669674f726967696e3b78707372002b636f6d2e7479706573" +
- "6166652e636f6e6669672e696d706c2e53696d706c65436f6e6669674f726967696e000000000000" +
- "000102000649000d656e644c696e654e756d62657249000a6c696e654e756d6265724c000e636f6d" +
- "6d656e74734f724e756c6c7400104c6a6176612f7574696c2f4c6973743b4c000b64657363726970" +
- "74696f6e7400124c6a6176612f6c616e672f537472696e673b4c000a6f726967696e547970657400" +
- "254c636f6d2f74797065736166652f636f6e6669672f696d706c2f4f726967696e547970653b4c00" +
- "0975726c4f724e756c6c71007e0009787000000002000000027074000b7465737420737472696e67" +
- "7e720023636f6d2e74797065736166652e636f6e6669672e696d706c2e4f726967696e5479706500" +
- "000000000000001200007872000e6a6176612e6c616e672e456e756d000000000000000012000078" +
- "7074000747454e455249437073720025636f6d2e74797065736166652e636f6e6669672e696d706c" +
- "2e53696d706c65436f6e66696700000000000000010200014c00066f626a65637474002f4c636f6d" +
- "2f74797065736166652f636f6e6669672f696d706c2f4162737472616374436f6e6669674f626a65" +
- "63743b787071007e00060000737200116a6176612e7574696c2e486173684d61700507dac1c31660" +
- "d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c77" +
- "08000000100000000a7400046f626a457372002b636f6d2e74797065736166652e636f6e6669672e" +
- "696d706c2e436f6e666967537562737469747574696f6e00000000000000010200035a001069676e" +
- "6f72657346616c6c6261636b7349000c7072656669784c656e6774684c000670696563657371007e" +
- "00087871007e00047371007e000700000008000000087071007e000c71007e000f70000000000073" +
- "7200146a6176612e7574696c2e4c696e6b65644c6973740c29535d4a608822030000787077040000" +
- "00017372002f636f6d2e74797065736166652e636f6e6669672e696d706c2e537562737469747574" +
- "696f6e45787072657373696f6e00000000000000010200025a00086f7074696f6e616c4c00047061" +
- "746874001f4c636f6d2f74797065736166652f636f6e6669672f696d706c2f506174683b78700073" +
- "72001d636f6d2e74797065736166652e636f6e6669672e696d706c2e506174680000000000000001" +
- "0200024c0005666972737471007e00094c000972656d61696e64657271007e001d78707400016173" +
- "71007e001f740001627371007e001f740001657078740007666f6f2e62617273720022636f6d2e74" +
- "797065736166652e636f6e6669672e696d706c2e436f6e666967496e740000000000000001020001" +
- "49000576616c756578720025636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e" +
- "6669674e756d62657200000000000000010200014c000c6f726967696e616c5465787471007e0009" +
- "7871007e00047371007e000700000009000000097071007e000c71007e000f707400023337000000" +
- "257400046f626a427371007e00177371007e000700000007000000077071007e000c71007e000f70" +
- "00000000007371007e001a7704000000017371007e001c007371007e001f740001617371007e001f" +
- "74000162707874000361727273720029636f6d2e74797065736166652e636f6e6669672e696d706c" +
- "2e53696d706c65436f6e6669674c69737400000000000000010200025a00087265736f6c7665644c" +
- "000576616c756571007e00087871007e00047371007e00070000000a0000000a7071007e000c7100" +
- "7e000f70007371007e001a7704000000067371007e00177371007e00070000000a0000000a707100" +
- "7e000c71007e000f7000000000007371007e001a7704000000017371007e001c007371007e001f74" +
- "0003666f6f70787371007e001771007e003b00000000007371007e001a7704000000017371007e00" +
- "1c007371007e001f740001617371007e001f740001627371007e001f7400016370787371007e0017" +
- "71007e003b00000000007371007e001a7704000000017371007e001c007371007e001f740007666f" +
- "6f2e62617270787371007e001771007e003b00000000007371007e001a7704000000017371007e00" +
- "1c007371007e001f7400046f626a427371007e001f7400016470787371007e001771007e003b0000" +
- "0000007371007e001a7704000000017371007e001c007371007e001f7400046f626a417371007e00" +
- "1f740001627371007e001f740001657371007e001f7400016670787371007e001771007e003b0000" +
- "0000007371007e001a7704000000017371007e001c007371007e001f7400046f626a457371007e00" +
- "1f740001667078787400046f626a417371007e00177371007e000700000006000000067071007e00" +
- "0c71007e000f7000000000007371007e001a7704000000017371007e001c007371007e001f740001" +
- "617078740001617371007e00007371007e000700000005000000057071007e000c71007e000f7073" +
- "71007e001171007e006f00007371007e00143f4000000000000c7708000000100000000174000162" +
- "7371007e00007371007e000700000005000000057071007e000c71007e000f707371007e00117100" +
- "7e007400007371007e00143f4000000000000c77080000001000000003740001647371007e001773" +
- "71007e000700000005000000057071007e000c71007e000f7000000000007371007e001a77040000" +
- "00017371007e001c007371007e001f740003666f6f7078740001657371007e00007371007e000700" +
- "000005000000057071007e000c71007e000f707371007e001171007e008000007371007e00143f40" +
- "00000000000c77080000001000000001740001667371007e001771007e007a00000000007371007e" +
- "001a7704000000017371007e001c007371007e001f740003666f6f707878740001637371007e0027" +
- "71007e007a7400023537000000397878740003666f6f7371007e00177371007e0007000000030000" +
- "00037071007e000c71007e000f7000000000007371007e001a7704000000017371007e001c007371" +
- "007e001f7400036261727078740008707472546f4172727371007e00177371007e00070000000b00" +
- "00000b7071007e000c71007e000f7000000000007371007e001a7704000000017371007e001c0073" +
- "71007e001f74000361727270787400036261727371007e00177371007e0007000000040000000470" +
- "71007e000c71007e000f7000000000007371007e001a7704000000017371007e001c007371007e00" +
- "1f740001617371007e001f740001627371007e001f740001637078740001787371007e0000737100" +
- "7e00070000000c0000000c7071007e000c71007e000f707371007e001171007e00a700007371007e" +
- "00143f4000000000000c77080000001000000001740001797371007e00007371007e00070000000c" +
- "0000000c7071007e000c71007e000f707371007e001171007e00ac00007371007e00143f40000000" +
- "00000c7708000000100000000174000d707472546f507472546f4172727371007e00177371007e00" +
- "070000000c0000000c7071007e000c71007e000f7000000000007371007e001a7704000000017371" +
- "007e001c007371007e001f740008707472546f4172727078787878"
-
- checkSerializableOldFormat(expectedSerialization, substComplexObject)
- }
-
- @Test
- def serializeUnresolvedObject() {
- val expectedSerialization = "" +
- "aced00057372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c6543" +
- "6f6e6669674f626a65637400000000000000010200035a001069676e6f72657346616c6c6261636b" +
- "735a00087265736f6c7665644c000576616c756574000f4c6a6176612f7574696c2f4d61703b7872" +
- "002d636f6d2e74797065736166652e636f6e6669672e696d706c2e4162737472616374436f6e6669" +
- "674f626a65637400000000000000010200014c0006636f6e6669677400274c636f6d2f7479706573" +
- "6166652f636f6e6669672f696d706c2f53696d706c65436f6e6669673b7872002c636f6d2e747970" +
- "65736166652e636f6e6669672e696d706c2e4162737472616374436f6e66696756616c7565000000" +
- "00000000010200014c00066f726967696e74002d4c636f6d2f74797065736166652f636f6e666967" +
- "2f696d706c2f53696d706c65436f6e6669674f726967696e3b78707372002b636f6d2e7479706573" +
- "6166652e636f6e6669672e696d706c2e53696d706c65436f6e6669674f726967696e000000000000" +
- "000102000649000d656e644c696e654e756d62657249000a6c696e654e756d6265724c000e636f6d" +
- "6d656e74734f724e756c6c7400104c6a6176612f7574696c2f4c6973743b4c000b64657363726970" +
- "74696f6e7400124c6a6176612f6c616e672f537472696e673b4c000a6f726967696e547970657400" +
- "254c636f6d2f74797065736166652f636f6e6669672f696d706c2f4f726967696e547970653b4c00" +
- "0975726c4f724e756c6c71007e0009787000000002000000027074000b7465737420737472696e67" +
- "7e720023636f6d2e74797065736166652e636f6e6669672e696d706c2e4f726967696e5479706500" +
- "000000000000001200007872000e6a6176612e6c616e672e456e756d000000000000000012000078" +
- "7074000747454e455249437073720025636f6d2e74797065736166652e636f6e6669672e696d706c" +
- "2e53696d706c65436f6e66696700000000000000010200014c00066f626a65637474002f4c636f6d" +
- "2f74797065736166652f636f6e6669672f696d706c2f4162737472616374436f6e6669674f626a65" +
- "63743b787071007e00060000737200116a6176612e7574696c2e486173684d61700507dac1c31660" +
- "d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c77" +
- "08000000100000000a7400046f626a4573720028636f6d2e74797065736166652e636f6e6669672e" +
- "696d706c2e436f6e6669675265666572656e6365000000000000000102000249000c707265666978" +
- "4c656e6774684c0004657870727400314c636f6d2f74797065736166652f636f6e6669672f696d70" +
- "6c2f537562737469747574696f6e45787072657373696f6e3b7871007e00047371007e0007000000" +
- "08000000087071007e000c71007e000f70000000007372002f636f6d2e74797065736166652e636f" +
- "6e6669672e696d706c2e537562737469747574696f6e45787072657373696f6e0000000000000001" +
- "0200025a00086f7074696f6e616c4c00047061746874001f4c636f6d2f74797065736166652f636f" +
- "6e6669672f696d706c2f506174683b7870007372001d636f6d2e74797065736166652e636f6e6669" +
- "672e696d706c2e5061746800000000000000010200024c0005666972737471007e00094c00097265" +
- "6d61696e64657271007e001c7870740001617371007e001e740001627371007e001e740001657074" +
- "0007666f6f2e62617273720022636f6d2e74797065736166652e636f6e6669672e696d706c2e436f" +
- "6e666967496e74000000000000000102000149000576616c756578720025636f6d2e747970657361" +
- "66652e636f6e6669672e696d706c2e436f6e6669674e756d62657200000000000000010200014c00" +
- "0c6f726967696e616c5465787471007e00097871007e00047371007e000700000009000000097071" +
- "007e000c71007e000f707400023337000000257400046f626a427371007e00177371007e00070000" +
- "0007000000077071007e000c71007e000f70000000007371007e001b007371007e001e7400016173" +
- "71007e001e740001627074000361727273720029636f6d2e74797065736166652e636f6e6669672e" +
- "696d706c2e53696d706c65436f6e6669674c69737400000000000000010200025a00087265736f6c" +
- "7665644c000576616c756571007e00087871007e00047371007e00070000000a0000000a7071007e" +
- "000c71007e000f7000737200146a6176612e7574696c2e4c696e6b65644c6973740c29535d4a6088" +
- "2203000078707704000000067371007e00177371007e00070000000a0000000a7071007e000c7100" +
- "7e000f70000000007371007e001b007371007e001e740003666f6f707371007e001771007e003a00" +
- "0000007371007e001b007371007e001e740001617371007e001e740001627371007e001e74000163" +
- "707371007e001771007e003a000000007371007e001b007371007e001e740007666f6f2e62617270" +
- "7371007e001771007e003a000000007371007e001b007371007e001e7400046f626a427371007e00" +
- "1e74000164707371007e001771007e003a000000007371007e001b007371007e001e7400046f626a" +
- "417371007e001e740001627371007e001e740001657371007e001e74000166707371007e00177100" +
- "7e003a000000007371007e001b007371007e001e7400046f626a457371007e001e74000166707874" +
- "00046f626a417371007e00177371007e000700000006000000067071007e000c71007e000f700000" +
- "00007371007e001b007371007e001e7400016170740001617371007e00007371007e000700000005" +
- "000000057071007e000c71007e000f707371007e001171007e006700007371007e00143f40000000" +
- "00000c77080000001000000001740001627371007e00007371007e00070000000500000005707100" +
- "7e000c71007e000f707371007e001171007e006c00007371007e00143f4000000000000c77080000" +
- "001000000003740001647371007e00177371007e000700000005000000057071007e000c71007e00" +
- "0f70000000007371007e001b007371007e001e740003666f6f70740001657371007e00007371007e" +
- "000700000005000000057071007e000c71007e000f707371007e001171007e007700007371007e00" +
- "143f4000000000000c77080000001000000001740001667371007e001771007e0072000000007371" +
- "007e001b007371007e001e740003666f6f7078740001637371007e002671007e0072740002353700" +
- "0000397878740003666f6f7371007e00177371007e000700000003000000037071007e000c71007e" +
- "000f70000000007371007e001b007371007e001e74000362617270740008707472546f4172727371" +
- "007e00177371007e00070000000b0000000b7071007e000c71007e000f70000000007371007e001b" +
- "007371007e001e740003617272707400036261727371007e00177371007e00070000000400000004" +
- "7071007e000c71007e000f70000000007371007e001b007371007e001e740001617371007e001e74" +
- "0001627371007e001e7400016370740001787371007e00007371007e00070000000c0000000c7071" +
- "007e000c71007e000f707371007e001171007e009a00007371007e00143f4000000000000c770800" +
- "00001000000001740001797371007e00007371007e00070000000c0000000c7071007e000c71007e" +
- "000f707371007e001171007e009f00007371007e00143f4000000000000c77080000001000000001" +
- "74000d707472546f507472546f4172727371007e00177371007e00070000000c0000000c7071007e" +
- "000c71007e000f70000000007371007e001b007371007e001e740008707472546f41727270787878"
- checkSerializable(expectedSerialization, substComplexObject)
+ def doNotSerializeUnresolvedObject() {
+ checkNotSerializable(substComplexObject)
}
// this is a weird test, it used to test fallback to system props which made more sense.
View
15 config/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
@@ -811,6 +811,9 @@ class ConfigTest extends TestUtils {
@Test
def test01Serializable() {
+ // we can't ever test an expected serialization here because it
+ // will have system props in it that vary by test system,
+ // and the ConfigOrigin in there will also vary by test system
val conf = ConfigFactory.load("test01")
val confCopy = checkSerializable(conf)
}
@@ -1005,4 +1008,16 @@ class ConfigTest extends TestUtils {
}
}
}
+
+ @Test
+ def serializeRoundTrip() {
+ for (i <- 1 to 10) {
+ val numString = i.toString
+ val name = "/test" + { if (numString.size == 1) "0" else "" } + numString
+ val conf = ConfigFactory.parseResourcesAnySyntax(classOf[ConfigTest], name,
+ ConfigParseOptions.defaults().setAllowMissing(false))
+ val resolved = conf.resolve()
+ checkSerializable(resolved)
+ }
+ }
}
View
363 config/src/test/scala/com/typesafe/config/impl/ConfigValueTest.scala
@@ -29,20 +29,9 @@ class ConfigValueTest extends TestUtils {
}
@Test
- def configOriginSerializable() {
- val expectedSerialization = "" +
- "aced00057372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c6543" +
- "6f6e6669674f726967696e000000000000000102000649000d656e644c696e654e756d6265724900" +
- "0a6c696e654e756d6265724c000e636f6d6d656e74734f724e756c6c7400104c6a6176612f757469" +
- "6c2f4c6973743b4c000b6465736372697074696f6e7400124c6a6176612f6c616e672f537472696e" +
- "673b4c000a6f726967696e547970657400254c636f6d2f74797065736166652f636f6e6669672f69" +
- "6d706c2f4f726967696e547970653b4c000975726c4f724e756c6c71007e00027870ffffffffffff" +
- "ffff70740003666f6f7e720023636f6d2e74797065736166652e636f6e6669672e696d706c2e4f72" +
- "6967696e5479706500000000000000001200007872000e6a6176612e6c616e672e456e756d000000" +
- "0000000000120000787074000747454e4552494370"
-
+ def configOriginNotSerializable() {
val a = SimpleConfigOrigin.newSimple("foo")
- checkSerializable(expectedSerialization, a)
+ checkNotSerializable(a)
}
@Test
@@ -59,23 +48,10 @@ class ConfigValueTest extends TestUtils {
@Test
def configIntSerializable() {
val expectedSerialization = "" +
- "aced000573720022636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e66696749" +
- "6e74000000000000000102000149000576616c756578720025636f6d2e74797065736166652e636f" +
- "6e6669672e696d706c2e436f6e6669674e756d62657200000000000000010200014c000c6f726967" +
- "696e616c546578747400124c6a6176612f6c616e672f537472696e673b7872002c636f6d2e747970" +
- "65736166652e636f6e6669672e696d706c2e4162737472616374436f6e66696756616c7565000000" +
- "00000000010200014c00066f726967696e74002d4c636f6d2f74797065736166652f636f6e666967" +
- "2f696d706c2f53696d706c65436f6e6669674f726967696e3b78707372002b636f6d2e7479706573" +
- "6166652e636f6e6669672e696d706c2e53696d706c65436f6e6669674f726967696e000000000000" +
- "000102000649000d656e644c696e654e756d62657249000a6c696e654e756d6265724c000e636f6d" +
- "6d656e74734f724e756c6c7400104c6a6176612f7574696c2f4c6973743b4c000b64657363726970" +
- "74696f6e71007e00024c000a6f726967696e547970657400254c636f6d2f74797065736166652f63" +
- "6f6e6669672f696d706c2f4f726967696e547970653b4c000975726c4f724e756c6c71007e000278" +
- "70ffffffffffffffff7074000b66616b65206f726967696e7e720023636f6d2e7479706573616665" +
- "2e636f6e6669672e696d706c2e4f726967696e5479706500000000000000001200007872000e6a61" +
- "76612e6c616e672e456e756d0000000000000000120000787074000747454e455249437070000000" +
- "2a"
-
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_902000000_-050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n090000000100010400000009020000002A0002_4_20103" +
+ "000000010001_x"
val a = intValue(42)
val b = checkSerializable(expectedSerialization, a)
assertEquals(42, b.unwrapped)
@@ -93,6 +69,19 @@ class ConfigValueTest extends TestUtils {
}
@Test
+ def configLongSerializable() {
+ val expectedSerialization = "" +
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_E02000000_9050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n090000000100010400000015030000000080000029000A" +
+ "_2_1_4_7_4_8_3_6_8_90103000000010001_x"
+
+ val a = longValue(Integer.MAX_VALUE + 42L)
+ val b = checkSerializable(expectedSerialization, a)
+ assertEquals(Integer.MAX_VALUE + 42L, b.unwrapped)
+ }
+
+ @Test
def configIntAndLongEquality() {
val longVal = longValue(42L)
val intValue = longValue(42)
@@ -105,6 +94,80 @@ class ConfigValueTest extends TestUtils {
checkNotEqualObjects(intValueB, longVal)
}
+ @Test
+ def configDoubleEquality() {
+ val a = doubleValue(3.14)
+ val sameAsA = doubleValue(3.14)
+ val b = doubleValue(4.14)
+
+ checkEqualObjects(a, a)
+ checkEqualObjects(a, sameAsA)
+ checkNotEqualObjects(a, b)
+ }
+
+ @Test
+ def configDoubleSerializable() {
+ val expectedSerialization = "" +
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w3F02000000_3050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n09000000010001040000000F0440091EB8_QEB851F0004" +
+ "_3_._1_40103000000010001_x"
+
+ val a = doubleValue(3.14)
+ val b = checkSerializable(expectedSerialization, a)
+ assertEquals(3.14, b.unwrapped)
+ }
+
+ @Test
+ def configIntAndDoubleEquality() {
+ val doubleVal = doubleValue(3.0)
+ val intValue = longValue(3)
+ val doubleValueB = doubleValue(4.0)
+ val intValueB = doubleValue(4)
+
+ checkEqualObjects(intValue, doubleVal)
+ checkEqualObjects(intValueB, doubleValueB)
+ checkNotEqualObjects(intValue, doubleValueB)
+ checkNotEqualObjects(intValueB, doubleVal)
+ }
+
+ @Test
+ def configNullSerializable() {
+ val expectedSerialization = "" +
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_10200000025050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n090000000100010400000001000103000000010001_x"
+
+ val a = nullValue()
+ val b = checkSerializable(expectedSerialization, a)
+ assertNull("b is null", b.unwrapped)
+ }
+
+ @Test
+ def configBooleanSerializable() {
+ val expectedSerialization = "" +
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_20200000026050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n09000000010001040000000201010103000000010001_x"
+
+ val a = boolValue(true)
+ val b = checkSerializable(expectedSerialization, a)
+ assertEquals(true, b.unwrapped)
+ }
+
+ @Test
+ def configStringSerializable() {
+ val expectedSerialization = "" +
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_F02000000_:050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n090000000100010400000016050013_T_h_e_ _q_u_i_c" +
+ "_k_ _b_r_o_w_n_ _f_o_x0103000000010001_x"
+
+ val a = stringValue("The quick brown fox")
+ val b = checkSerializable(expectedSerialization, a)
+ assertEquals("The quick brown fox", b.unwrapped)
+ }
+
private def configMap(pairs: (String, Int)*): java.util.Map[String, AbstractConfigValue] = {
val m = new java.util.HashMap[String, AbstractConfigValue]()
for (p <- pairs) {
@@ -149,35 +212,11 @@ class ConfigValueTest extends TestUtils {
@Test
def configObjectSerializable() {
val expectedSerialization = "" +
- "aced00057372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c6543" +
- "6f6e6669674f626a65637400000000000000010200035a001069676e6f72657346616c6c6261636b" +
- "735a00087265736f6c7665644c000576616c756574000f4c6a6176612f7574696c2f4d61703b7872" +
- "002d636f6d2e74797065736166652e636f6e6669672e696d706c2e4162737472616374436f6e6669" +
- "674f626a65637400000000000000010200014c0006636f6e6669677400274c636f6d2f7479706573" +
- "6166652f636f6e6669672f696d706c2f53696d706c65436f6e6669673b7872002c636f6d2e747970" +
- "65736166652e636f6e6669672e696d706c2e4162737472616374436f6e66696756616c7565000000" +
- "00000000010200014c00066f726967696e74002d4c636f6d2f74797065736166652f636f6e666967" +
- "2f696d706c2f53696d706c65436f6e6669674f726967696e3b78707372002b636f6d2e7479706573" +
- "6166652e636f6e6669672e696d706c2e53696d706c65436f6e6669674f726967696e000000000000" +
- "000102000649000d656e644c696e654e756d62657249000a6c696e654e756d6265724c000e636f6d" +
- "6d656e74734f724e756c6c7400104c6a6176612f7574696c2f4c6973743b4c000b64657363726970" +
- "74696f6e7400124c6a6176612f6c616e672f537472696e673b4c000a6f726967696e547970657400" +
- "254c636f6d2f74797065736166652f636f6e6669672f696d706c2f4f726967696e547970653b4c00" +
- "0975726c4f724e756c6c71007e00097870ffffffffffffffff7074000b66616b65206f726967696e" +
- "7e720023636f6d2e74797065736166652e636f6e6669672e696d706c2e4f726967696e5479706500" +
- "000000000000001200007872000e6a6176612e6c616e672e456e756d000000000000000012000078" +
- "7074000747454e455249437073720025636f6d2e74797065736166652e636f6e6669672e696d706c" +
- "2e53696d706c65436f6e66696700000000000000010200014c00066f626a65637474002f4c636f6d" +
- "2f74797065736166652f636f6e6669672f696d706c2f4162737472616374436f6e6669674f626a65" +
- "63743b787071007e00060001737200116a6176612e7574696c2e486173684d61700507dac1c31660" +
- "d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c77" +
- "0800000010000000037400016273720022636f6d2e74797065736166652e636f6e6669672e696d70" +
- "6c2e436f6e666967496e74000000000000000102000149000576616c756578720025636f6d2e7479" +
- "7065736166652e636f6e6669672e696d706c2e436f6e6669674e756d626572000000000000000102" +
- "00014c000c6f726967696e616c5465787471007e00097871007e00047371007e0007ffffffffffff" +
- "ffff7071007e000c71007e000f707000000002740001637371007e00177371007e0007ffffffffff" +
- "ffffff7071007e000c71007e000f707000000003740001617371007e00177371007e0007ffffffff" +
- "ffffffff7071007e000c71007e000f70700000000178"
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_z02000000_n050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n0900000001000104000000_J07000000030001_a050000" +
+ "000101040000000802000000010001_1010001_c050000000101040000000802000000030001_301" +
+ "0001_b050000000101040000000802000000020001_2010103000000010001_x"
val aMap = configMap("a" -> 1, "b" -> 2, "c" -> 3)
val a = new SimpleConfigObject(fakeOrigin(), aMap)
@@ -188,6 +227,23 @@ class ConfigValueTest extends TestUtils {
}
@Test
+ def configConfigSerializable() {
+ val expectedSerialization = "" +
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_z02000000_n050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n0900000001000104000000_J07000000030001_a050000" +
+ "000101040000000802000000010001_1010001_c050000000101040000000802000000030001_301" +
+ "0001_b050000000101040000000802000000020001_2010103000000010101_x"
+
+ val aMap = configMap("a" -> 1, "b" -> 2, "c" -> 3)
+ val a = new SimpleConfigObject(fakeOrigin(), aMap)
+ val b = checkSerializable(expectedSerialization, a.toConfig())
+ assertEquals(1, b.getInt("a"))
+ // check that deserialized Config and ConfigObject refer to each other
+ assertTrue(b.root.toConfig eq b)
+ }
+
+ @Test
def configListEquality() {
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
val aList = new SimpleConfigList(fakeOrigin(), aScalaSeq.asJava)
@@ -203,28 +259,11 @@ class ConfigValueTest extends TestUtils {
@Test
def configListSerializable() {
val expectedSerialization = "" +
- "aced000573720029636f6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c6543" +
- "6f6e6669674c69737400000000000000010200025a00087265736f6c7665644c000576616c756574" +
- "00104c6a6176612f7574696c2f4c6973743b7872002c636f6d2e74797065736166652e636f6e6669" +
- "672e696d706c2e4162737472616374436f6e66696756616c756500000000000000010200014c0006" +
- "6f726967696e74002d4c636f6d2f74797065736166652f636f6e6669672f696d706c2f53696d706c" +
- "65436f6e6669674f726967696e3b78707372002b636f6d2e74797065736166652e636f6e6669672e" +
- "696d706c2e53696d706c65436f6e6669674f726967696e000000000000000102000649000d656e64" +
- "4c696e654e756d62657249000a6c696e654e756d6265724c000e636f6d6d656e74734f724e756c6c" +
- "71007e00014c000b6465736372697074696f6e7400124c6a6176612f6c616e672f537472696e673b" +
- "4c000a6f726967696e547970657400254c636f6d2f74797065736166652f636f6e6669672f696d70" +
- "6c2f4f726967696e547970653b4c000975726c4f724e756c6c71007e00067870ffffffffffffffff" +
- "7074000b66616b65206f726967696e7e720023636f6d2e74797065736166652e636f6e6669672e69" +
- "6d706c2e4f726967696e5479706500000000000000001200007872000e6a6176612e6c616e672e45" +
- "6e756d0000000000000000120000787074000747454e455249437001737200146a6176612e757469" +
- "6c2e4c696e6b65644c6973740c29535d4a608822030000787077040000000373720022636f6d2e74" +
- "797065736166652e636f6e6669672e696d706c2e436f6e666967496e740000000000000001020001" +
- "49000576616c756578720025636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e" +
- "6669674e756d62657200000000000000010200014c000c6f726967696e616c5465787471007e0006" +
- "7871007e00027371007e0005ffffffffffffffff7071007e000971007e000c707000000001737100" +
- "7e00107371007e0005ffffffffffffffff7071007e000971007e000c7070000000027371007e0010" +
- "7371007e0005ffffffffffffffff7071007e000971007e000c70700000000378"
-
+ "ACED0005_s_r00_._c_o_m_._t_y_p_e_s_a_f_e_._c_o_n_f_i_g_._i_m_p_l_._S_e_r_i_a_l_i" +
+ "_z_e_d_C_o_n_f_i_g_V_a_l_u_e00000000000000010C0000_x_p_w_q02000000_e050000001906" +
+ "0000000D000B_f_a_k_e_ _o_r_i_g_i_n0900000001000104000000_A0600000003050000000101" +
+ "040000000802000000010001_101050000000101040000000802000000020001_201050000000101" +
+ "040000000802000000030001_3010103000000010001_x"
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
val aList = new SimpleConfigList(fakeOrigin(), aScalaSeq.asJava)
val bList = checkSerializable(expectedSerialization, aList)
@@ -246,32 +285,9 @@ class ConfigValueTest extends TestUtils {
}
@Test
- def configSubstitutionSerializable() {
- val expectedSerialization = "" +
- "aced00057372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e66696753" +
- "7562737469747574696f6e00000000000000010200035a001069676e6f72657346616c6c6261636b" +
- "7349000c7072656669784c656e6774684c00067069656365737400104c6a6176612f7574696c2f4c" +
- "6973743b7872002c636f6d2e74797065736166652e636f6e6669672e696d706c2e41627374726163" +
- "74436f6e66696756616c756500000000000000010200014c00066f726967696e74002d4c636f6d2f" +
- "74797065736166652f636f6e6669672f696d706c2f53696d706c65436f6e6669674f726967696e3b" +
- "78707372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c65436f6e" +
- "6669674f726967696e000000000000000102000649000d656e644c696e654e756d62657249000a6c" +
- "696e654e756d6265724c000e636f6d6d656e74734f724e756c6c71007e00014c000b646573637269" +
- "7074696f6e7400124c6a6176612f6c616e672f537472696e673b4c000a6f726967696e5479706574" +
- "00254c636f6d2f74797065736166652f636f6e6669672f696d706c2f4f726967696e547970653b4c" +
- "000975726c4f724e756c6c71007e00067870ffffffffffffffff7074000b66616b65206f72696769" +
- "6e7e720023636f6d2e74797065736166652e636f6e6669672e696d706c2e4f726967696e54797065" +
- "00000000000000001200007872000e6a6176612e6c616e672e456e756d0000000000000000120000" +
- "787074000747454e45524943700000000000737200146a6176612e7574696c2e4c696e6b65644c69" +
- "73740c29535d4a60882203000078707704000000017372002f636f6d2e74797065736166652e636f" +
- "6e6669672e696d706c2e537562737469747574696f6e45787072657373696f6e0000000000000001" +
- "0200025a00086f7074696f6e616c4c00047061746874001f4c636f6d2f74797065736166652f636f" +
- "6e6669672f696d706c2f506174683b7870007372001d636f6d2e74797065736166652e636f6e6669" +
- "672e696d706c2e5061746800000000000000010200024c0005666972737471007e00064c00097265" +
- "6d61696e64657271007e00117870740003666f6f7078"
-
+ def configSubstitutionNotSerializable() {
val a = subst("foo")
- val b = checkSerializable(expectedSerialization, a)
+ checkNotSerializable(a)
}
@Test
@@ -293,33 +309,10 @@ class ConfigValueTest extends TestUtils {
}
@Test
- def configReferenceSerializable() {
- val expectedSerialization = "" +
- "aced000573720028636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e66696752" +
- "65666572656e6365000000000000000102000249000c7072656669784c656e6774684c0004657870" +
- "727400314c636f6d2f74797065736166652f636f6e6669672f696d706c2f53756273746974757469" +
- "6f6e45787072657373696f6e3b7872002c636f6d2e74797065736166652e636f6e6669672e696d70" +
- "6c2e4162737472616374436f6e66696756616c756500000000000000010200014c00066f72696769" +
- "6e74002d4c636f6d2f74797065736166652f636f6e6669672f696d706c2f53696d706c65436f6e66" +
- "69674f726967696e3b78707372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e" +
- "53696d706c65436f6e6669674f726967696e000000000000000102000649000d656e644c696e654e" +
- "756d62657249000a6c696e654e756d6265724c000e636f6d6d656e74734f724e756c6c7400104c6a" +
- "6176612f7574696c2f4c6973743b4c000b6465736372697074696f6e7400124c6a6176612f6c616e" +
- "672f537472696e673b4c000a6f726967696e547970657400254c636f6d2f74797065736166652f63" +
- "6f6e6669672f696d706c2f4f726967696e547970653b4c000975726c4f724e756c6c71007e000778" +
- "70ffffffffffffffff7074000b66616b65206f726967696e7e720023636f6d2e7479706573616665" +
- "2e636f6e6669672e696d706c2e4f726967696e5479706500000000000000001200007872000e6a61" +
- "76612e6c616e672e456e756d0000000000000000120000787074000747454e455249437000000000" +
- "7372002f636f6d2e74797065736166652e636f6e6669672e696d706c2e537562737469747574696f" +
- "6e45787072657373696f6e00000000000000010200025a00086f7074696f6e616c4c000470617468" +
- "74001f4c636f6d2f74797065736166652f636f6e6669672f696d706c2f506174683b787000737200" +
- "1d636f6d2e74797065736166652e636f6e6669672e696d706c2e5061746800000000000000010200" +
- "024c0005666972737471007e00074c000972656d61696e64657271007e00107870740003666f6f70"
-
+ def configReferenceNotSerializable() {
val a = subst("foo").delegate()
assertTrue("wrong type " + a, a.isInstanceOf[ConfigReference])
- val b = checkSerializable(expectedSerialization, a)
- assertTrue("wrong type " + b, b.isInstanceOf[ConfigReference])
+ checkNotSerializable(a)
}
@Test
@@ -340,39 +333,10 @@ class ConfigValueTest extends TestUtils {
}
@Test
- def configConcatenationSerializable() {
- val expectedSerialization = "" +
- "aced00057372002c636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e66696743" +
- "6f6e636174656e6174696f6e00000000000000010200014c00067069656365737400104c6a617661" +
- "2f7574696c2f4c6973743b7872002c636f6d2e74797065736166652e636f6e6669672e696d706c2e" +
- "4162737472616374436f6e66696756616c756500000000000000010200014c00066f726967696e74" +
- "002d4c636f6d2f74797065736166652f636f6e6669672f696d706c2f53696d706c65436f6e666967" +
- "4f726967696e3b78707372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e5369" +
- "6d706c65436f6e6669674f726967696e000000000000000102000649000d656e644c696e654e756d" +
- "62657249000a6c696e654e756d6265724c000e636f6d6d656e74734f724e756c6c71007e00014c00" +
- "0b6465736372697074696f6e7400124c6a6176612f6c616e672f537472696e673b4c000a6f726967" +
- "696e547970657400254c636f6d2f74797065736166652f636f6e6669672f696d706c2f4f72696769" +
- "6e547970653b4c000975726c4f724e756c6c71007e00067870ffffffffffffffff7074000b66616b" +
- "65206f726967696e7e720023636f6d2e74797065736166652e636f6e6669672e696d706c2e4f7269" +
- "67696e5479706500000000000000001200007872000e6a6176612e6c616e672e456e756d00000000" +
- "00000000120000787074000747454e4552494370737200146a6176612e7574696c2e4c696e6b6564" +
- "4c6973740c29535d4a608822030000787077040000000373720025636f6d2e74797065736166652e" +
- "636f6e6669672e696d706c2e436f6e666967537472696e6700000000000000010200014c00057661" +
- "6c756571007e00067871007e000271007e000874000673746172743c73720028636f6d2e74797065" +
- "736166652e636f6e6669672e696d706c2e436f6e6669675265666572656e63650000000000000001" +
- "02000249000c7072656669784c656e6774684c0004657870727400314c636f6d2f74797065736166" +
- "652f636f6e6669672f696d706c2f537562737469747574696f6e45787072657373696f6e3b787100" +
- "7e000271007e0008000000007372002f636f6d2e74797065736166652e636f6e6669672e696d706c" +
- "2e537562737469747574696f6e45787072657373696f6e00000000000000010200025a00086f7074" +
- "696f6e616c4c00047061746874001f4c636f6d2f74797065736166652f636f6e6669672f696d706c" +
- "2f506174683b7870007372001d636f6d2e74797065736166652e636f6e6669672e696d706c2e5061" +
- "746800000000000000010200024c0005666972737471007e00064c000972656d61696e6465727100" +
- "7e00177870740003666f6f707371007e001071007e00087400043e656e6478"
-
+ def configConcatenationNotSerializable() {
val a = substInString("foo").delegate()
assertTrue("wrong type " + a, a.isInstanceOf[ConfigConcatenation])
- val b = checkSerializable(expectedSerialization, a)
- assertTrue("wrong type " + b, b.isInstanceOf[ConfigConcatenation])
+ checkNotSerializable(a)
}
@Test
@@ -404,39 +368,11 @@ class ConfigValueTest extends TestUtils {
}
@Test
- def configDelayedMergeSerializable() {
- val expectedSerialization = "" +
- "aced00057372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e66696744" +
- "656c617965644d6572676500000000000000010200025a001069676e6f72657346616c6c6261636b" +
- "734c0005737461636b7400104c6a6176612f7574696c2f4c6973743b7872002c636f6d2e74797065" +
- "736166652e636f6e6669672e696d706c2e4162737472616374436f6e66696756616c756500000000" +
- "000000010200014c00066f726967696e74002d4c636f6d2f74797065736166652f636f6e6669672f" +
- "696d706c2f53696d706c65436f6e6669674f726967696e3b78707372002b636f6d2e747970657361" +
- "66652e636f6e6669672e696d706c2e53696d706c65436f6e6669674f726967696e00000000000000" +
- "0102000649000d656e644c696e654e756d62657249000a6c696e654e756d6265724c000e636f6d6d" +
- "656e74734f724e756c6c71007e00014c000b6465736372697074696f6e7400124c6a6176612f6c61" +
- "6e672f537472696e673b4c000a6f726967696e547970657400254c636f6d2f74797065736166652f" +
- "636f6e6669672f696d706c2f4f726967696e547970653b4c000975726c4f724e756c6c71007e0006" +
- "7870ffffffffffffffff7074000b66616b65206f726967696e7e720023636f6d2e74797065736166" +
- "652e636f6e6669672e696d706c2e4f726967696e5479706500000000000000001200007872000e6a" +
- "6176612e6c616e672e456e756d0000000000000000120000787074000747454e4552494370007372" +
- "00146a6176612e7574696c2e4c696e6b65644c6973740c29535d4a60882203000078707704000000" +
- "027372002b636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e66696753756273" +
- "7469747574696f6e00000000000000010200035a001069676e6f72657346616c6c6261636b734900" +
- "0c7072656669784c656e6774684c000670696563657371007e00017871007e00027371007e0005ff" +
- "ffffffffffffff7071007e000971007e000c7000000000007371007e000e7704000000017372002f" +
- "636f6d2e74797065736166652e636f6e6669672e696d706c2e537562737469747574696f6e457870" +
- "72657373696f6e00000000000000010200025a00086f7074696f6e616c4c00047061746874001f4c" +
- "636f6d2f74797065736166652f636f6e6669672f696d706c2f506174683b7870007372001d636f6d" +
- "2e74797065736166652e636f6e6669672e696d706c2e5061746800000000000000010200024c0005" +
- "666972737471007e00064c000972656d61696e64657271007e00157870740003666f6f7078737100" +
- "7e00107371007e0005ffffffffffffffff7071007e000971007e000c7000000000007371007e000e" +
- "7704000000017371007e0014007371007e0017740003626172707878"
-
+ def configDelayedMergeNotSerializable() {
val s1 = subst("foo")
val s2 = subst("bar")
val a = new ConfigDelayedMerge(fakeOrigin(), List[AbstractConfigValue](s1, s2).asJava)
- val b = checkSerializable(expectedSerialization, a)
+ checkNotSerializable(a)
}
@Test
@@ -454,51 +390,12 @@ class ConfigValueTest extends TestUtils {
}
@Test
- def configDelayedMergeObjectSerializable() {
- val expectedSerialization = "" +
- "aced000573720031636f6d2e74797065736166652e636f6e6669672e696d706c2e436f6e66696744" +
- "656c617965644d657267654f626a65637400000000000000010200025a001069676e6f7265734661" +
- "6c6c6261636b734c0005737461636b7400104c6a6176612f7574696c2f4c6973743b7872002d636f" +
- "6d2e74797065736166652e636f6e6669672e696d706c2e4162737472616374436f6e6669674f626a" +
- "65637400000000000000010200014c0006636f6e6669677400274c636f6d2f74797065736166652f" +
- "636f6e6669672f696d706c2f53696d706c65436f6e6669673b7872002c636f6d2e74797065736166" +
- "652e636f6e6669672e696d706c2e4162737472616374436f6e66696756616c756500000000000000" +
- "010200014c00066f726967696e74002d4c636f6d2f74797065736166652f636f6e6669672f696d70" +
- "6c2f53696d706c65436f6e6669674f726967696e3b78707372002b636f6d2e74797065736166652e" +
- "636f6e6669672e696d706c2e53696d706c65436f6e6669674f726967696e00000000000000010200" +
- "0649000d656e644c696e654e756d62657249000a6c696e654e756d6265724c000e636f6d6d656e74" +
- "734f724e756c6c71007e00014c000b6465736372697074696f6e7400124c6a6176612f6c616e672f" +
- "537472696e673b4c000a6f726967696e547970657400254c636f6d2f74797065736166652f636f6e" +
- "6669672f696d706c2f4f726967696e547970653b4c000975726c4f724e756c6c71007e00087870ff" +
- "ffffffffffffff7074000b66616b65206f726967696e7e720023636f6d2e74797065736166652e63" +
- "6f6e6669672e696d706c2e4f726967696e5479706500000000000000001200007872000e6a617661" +
- "2e6c616e672e456e756d0000000000000000120000787074000747454e455249437073720025636f" +
- "6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c65436f6e6669670000000000" +
- "0000010200014c00066f626a65637474002f4c636f6d2f74797065736166652f636f6e6669672f69" +
- "6d706c2f4162737472616374436f6e6669674f626a6563743b787071007e000600737200146a6176" +
- "612e7574696c2e4c696e6b65644c6973740c29535d4a60882203000078707704000000037372002b" +
- "636f6d2e74797065736166652e636f6e6669672e696d706c2e53696d706c65436f6e6669674f626a" +
- "65637400000000000000010200035a001069676e6f72657346616c6c6261636b735a00087265736f" +
- "6c7665644c000576616c756574000f4c6a6176612f7574696c2f4d61703b7871007e00027371007e" +
- "0007ffffffffffffffff7074000c656d70747920636f6e66696771007e000e707371007e00107100" +
- "7e001700017372001e6a6176612e7574696c2e436f6c6c656374696f6e7324456d7074794d617059" +
- "3614855adce7d002000078707372002b636f6d2e74797065736166652e636f6e6669672e696d706c" +
- "2e436f6e666967537562737469747574696f6e00000000000000010200035a001069676e6f726573" +
- "46616c6c6261636b7349000c7072656669784c656e6774684c000670696563657371007e00017871" +
- "007e00047371007e0007ffffffffffffffff7071007e000b71007e000e7000000000007371007e00" +
- "137704000000017372002f636f6d2e74797065736166652e636f6e6669672e696d706c2e53756273" +
- "7469747574696f6e45787072657373696f6e00000000000000010200025a00086f7074696f6e616c" +
- "4c00047061746874001f4c636f6d2f74797065736166652f636f6e6669672f696d706c2f50617468" +
- "3b7870007372001d636f6d2e74797065736166652e636f6e6669672e696d706c2e50617468000000" +
- "00000000010200024c0005666972737471007e00084c000972656d61696e64657271007e00227870" +
- "740003666f6f70787371007e001d7371007e0007ffffffffffffffff7071007e000b71007e000e70" +
- "00000000007371007e00137704000000017371007e0021007371007e0024740003626172707878"
-
+ def configDelayedMergeObjectNotSerializable() {
val empty = SimpleConfigObject.empty()
val s1 = subst("foo")
val s2 = subst("bar")
val a = new ConfigDelayedMergeObject(fakeOrigin(), List[AbstractConfigValue](empty, s1, s2).asJava)
- val b = checkSerializable(expectedSerialization, a)
+ checkNotSerializable(a)
}
@Test
View
94 config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
@@ -17,11 +17,12 @@ import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.io.ByteArrayInputStream
import java.io.ObjectInputStream
-import org.apache.commons.codec.binary.Hex
+import java.io.NotSerializableException
import scala.annotation.tailrec
import java.net.URL
import java.util.concurrent.Executors
import java.util.concurrent.Callable
+import com.typesafe.config._
abstract trait TestUtils {
protected def intercept[E <: Throwable: Manifest](block: => Unit): E = {
@@ -91,6 +92,54 @@ abstract trait TestUtils {
checkNotEqualToRandomOtherThing(b)
}
+ private val hexDigits = {
+ val a = new Array[Char](16)
+ var i = 0
+ for (c <- '0' to '9') {
+ a(i) = c
+ i += 1
+ }
+ for (c <- 'A' to 'F') {
+ a(i) = c
+ i += 1
+ }
+ a
+ }
+
+ private def encodeLegibleBinary(bytes: Array[Byte]): String = {
+ val sb = new java.lang.StringBuilder()
+ for (b <- bytes) {
+ if ((b >= 'a' && b <= 'z') ||
+ (b >= 'A' && b <= 'Z') ||
+ (b >= '0' && b <= '9') ||
+ b == '-' || b == ':' || b == '.' || b == '/' || b == ' ') {
+ sb.append('_')
+ sb.appendCodePoint(b.asInstanceOf[Char])
+ } else {
+ sb.appendCodePoint(hexDigits((b & 0xF0) >> 4))
+ sb.appendCodePoint(hexDigits(b & 0x0F))
+ }
+ }
+ sb.toString
+ }
+
+ private def decodeLegibleBinary(s: String): Array[Byte] = {
+ val a = new Array[Byte](s.length() / 2)
+ var i = 0
+ var j = 0
+ while (i < s.length()) {
+ val sub = s.substring(i, i + 2)
+ i += 2
+ if (sub.charAt(0) == '_') {
+ a(j) = charWrapper(sub.charAt(1)).byteValue
+ } else {
+ a(j) = Integer.parseInt(sub, 16).byteValue
+ }
+ j += 1
+ }
+ a
+ }
+
private def copyViaSerialize(o: java.io.Serializable): AnyRef = {
val byteStream = new ByteArrayOutputStream()
val objectStream = new ObjectOutputStream(byteStream)
@@ -105,17 +154,20 @@ abstract trait TestUtils {
protected def checkSerializationCompat[T: Manifest](expectedHex: String, o: T, changedOK: Boolean = false): Unit = {
// be sure we can still deserialize the old one
- val inStream = new ByteArrayInputStream(Hex.decodeHex(expectedHex.toCharArray()))
- val inObjectStream = new ObjectInputStream(inStream)
+ val inStream = new ByteArrayInputStream(decodeLegibleBinary(expectedHex))
var failure: Option[Exception] = None
+ var inObjectStream: ObjectInputStream = null
val deserialized = try {
+ inObjectStream = new ObjectInputStream(inStream) // this can throw too
inObjectStream.readObject()
} catch {
case e: Exception =>
failure = Some(e)
null
+ } finally {
+ if (inObjectStream != null)
+ inObjectStream.close()
}
- inObjectStream.close()
val why = failure.map({ e => ": " + e.getClass.getSimpleName + ": " + e.getMessage }).getOrElse("")
@@ -123,7 +175,7 @@ abstract trait TestUtils {
val objectStream = new ObjectOutputStream(byteStream)
objectStream.writeObject(o)
objectStream.close()
- val hex = Hex.encodeHexString(byteStream.toByteArray())
+ val hex = encodeLegibleBinary(byteStream.toByteArray())
def showCorrectResult(): Unit = {
if (expectedHex != hex) {
@tailrec
@@ -156,6 +208,15 @@ abstract trait TestUtils {
}
}
+ protected def checkNotSerializable(o: AnyRef): Unit = {