mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
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.
This commit is contained in:
parent
d14d8cae78
commit
388d85fb5d
16
NEWS.md
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"
|
||||
|
@ -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 : _*)
|
||||
|
@ -18,8 +18,6 @@ import com.typesafe.config.ConfigValueType;
|
||||
|
||||
abstract class AbstractConfigObject extends AbstractConfigValue implements ConfigObject {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
final private SimpleConfig config;
|
||||
|
||||
protected AbstractConfigObject(ConfigOrigin origin) {
|
||||
|
@ -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 @@ import com.typesafe.config.ConfigValue;
|
||||
* 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;
|
||||
|
||||
|
@ -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 @@ final class ConfigBoolean extends AbstractConfigValue {
|
||||
protected ConfigBoolean newCopy(ConfigOrigin origin) {
|
||||
return new ConfigBoolean(origin, value);
|
||||
}
|
||||
|
||||
// serialization all goes through SerializedConfigValue
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return new SerializedConfigValue(this);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ import com.typesafe.config.ConfigValueType;
|
||||
* 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 @@ final class ConfigConcatenation extends AbstractConfigValue implements Unmergeab
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -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 @@ import com.typesafe.config.ConfigValueType;
|
||||
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 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements Unmergeabl
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ import com.typesafe.config.ConfigValue;
|
||||
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 @@ final class ConfigDelayedMergeObject extends AbstractConfigObject implements Unm
|
||||
"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));
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ final class ConfigDouble extends ConfigNumber {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ final class ConfigInt extends ConfigNumber {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ final class ConfigLong extends ConfigNumber {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ import com.typesafe.config.ConfigValueType;
|
||||
* 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 @@ final class ConfigNull extends AbstractConfigValue {
|
||||
protected ConfigNull newCopy(ConfigOrigin origin) {
|
||||
return new ConfigNull(origin);
|
||||
}
|
||||
|
||||
// serialization all goes through SerializedConfigValue
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return new SerializedConfigValue(this);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ abstract class ConfigNumber extends AbstractConfigValue {
|
||||
return new ConfigDouble(origin, number, originalText);
|
||||
}
|
||||
}
|
||||
|
||||
// serialization all goes through SerializedConfigValue
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return new SerializedConfigValue(this);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import com.typesafe.config.ConfigValueType;
|
||||
* 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()
|
||||
|
@ -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 @@ final class ConfigString extends AbstractConfigValue {
|
||||
protected ConfigString newCopy(ConfigOrigin origin) {
|
||||
return new ConfigString(origin, value);
|
||||
}
|
||||
|
||||
// serialization all goes through SerializedConfigValue
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return new SerializedConfigValue(this);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ package com.typesafe.config.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@ -18,8 +19,7 @@ import com.typesafe.config.ConfigValueType;
|
||||
* and ConfigConcatenation.
|
||||
*/
|
||||
@Deprecated
|
||||
final class ConfigSubstitution extends AbstractConfigValue implements
|
||||
Unmergeable {
|
||||
final class ConfigSubstitution extends AbstractConfigValue implements Unmergeable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
// caution: ordinals used in serialization
|
||||
enum OriginType {
|
||||
GENERIC,
|
||||
FILE,
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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 @@ final class SimpleConfig implements Config, MergeableValue, Serializable {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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.ConfigOrigin;
|
||||
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 class SimpleConfigList extends AbstractConfigValue implements ConfigList {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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.ConfigObject;
|
||||
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 class SimpleConfigObject extends AbstractConfigObject {
|
||||
baseOrigin.description() + " (not found)"),
|
||||
Collections.<String, AbstractConfigValue> emptyMap());
|
||||
}
|
||||
|
||||
// serialization all goes through SerializedConfigValue
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return new SerializedConfigValue(this);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ final class SimpleConfigOrigin implements ConfigOrigin, Serializable {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
@ -92,6 +68,19 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(a, b)
|
||||
}
|
||||
|
||||
@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)
|
||||
@ -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)
|
||||
@ -187,6 +226,23 @@ class ConfigValueTest extends TestUtils {
|
||||
assertTrue(b.toConfig.root eq b)
|
||||
}
|
||||
|
||||
@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 }
|
||||
@ -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
|
||||
|
@ -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 = {
|
||||
val byteStream = new ByteArrayOutputStream()
|
||||
val objectStream = new ObjectOutputStream(byteStream)
|
||||
val e = intercept[NotSerializableException] {
|
||||
objectStream.writeObject(o)
|
||||
}
|
||||
objectStream.close()
|
||||
}
|
||||
|
||||
protected def checkSerializable[T: Manifest](expectedHex: String, o: T): T = {
|
||||
val t = checkSerializable(o)
|
||||
checkSerializationCompat(expectedHex, o)
|
||||
@ -183,6 +244,7 @@ abstract trait TestUtils {
|
||||
"possibly caused by http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627",
|
||||
nf)
|
||||
case e: Exception =>
|
||||
System.err.println(e.getStackTraceString);
|
||||
throw new AssertionError("failed to make a copy via serialization", e)
|
||||
}
|
||||
|
||||
@ -190,10 +252,32 @@ abstract trait TestUtils {
|
||||
manifest[T].erasure.isAssignableFrom(b.getClass))
|
||||
|
||||
checkEqualObjects(a, b)
|
||||
checkEqualOrigins(a, b)
|
||||
|
||||
b.asInstanceOf[T]
|
||||
}
|
||||
|
||||
// origin() is not part of value equality but is serialized, so
|
||||
// we check it separately
|
||||
protected def checkEqualOrigins[T](a: T, b: T): Unit = {
|
||||
import scala.collection.JavaConverters._
|
||||
(a, b) match {
|
||||
case (obj1: ConfigObject, obj2: ConfigObject) =>
|
||||
assertEquals(obj1.origin(), obj2.origin())
|
||||
for (e <- obj1.entrySet().asScala) {
|
||||
checkEqualOrigins(e.getValue(), obj2.get(e.getKey()))
|
||||
}
|
||||
case (list1: ConfigList, list2: ConfigList) =>
|
||||
assertEquals(list1.origin(), list2.origin())
|
||||
for ((v1, v2) <- list1.asScala zip list2.asScala) {
|
||||
checkEqualOrigins(v1, v2)
|
||||
}
|
||||
case (value1: ConfigValue, value2: ConfigValue) =>
|
||||
assertEquals(value1.origin(), value2.origin())
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
def fakeOrigin() = {
|
||||
SimpleConfigOrigin.newSimple("fake origin")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user