mirror of
https://github.com/lightbend/config.git
synced 2025-03-22 15:20:26 +08:00
Make concrete Config and ConfigValue serializable
This commit is contained in:
parent
846c8c116a
commit
2d8e42686c
@ -3,6 +3,8 @@
|
||||
*/
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.typesafe.config.ConfigException;
|
||||
import com.typesafe.config.ConfigMergeable;
|
||||
import com.typesafe.config.ConfigOrigin;
|
||||
@ -16,7 +18,7 @@ import com.typesafe.config.ConfigValue;
|
||||
* improperly-factored and non-modular code. Please don't add parent().
|
||||
*
|
||||
*/
|
||||
abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
|
||||
abstract class AbstractConfigValue implements ConfigValue, MergeableValue, Serializable {
|
||||
|
||||
final private SimpleConfigOrigin origin;
|
||||
|
||||
|
@ -3,12 +3,13 @@
|
||||
*/
|
||||
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 {
|
||||
final class Path implements Serializable {
|
||||
|
||||
final private String first;
|
||||
final private Path remainder;
|
||||
|
@ -3,6 +3,7 @@
|
||||
*/
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -28,7 +29,7 @@ import com.typesafe.config.ConfigValueType;
|
||||
* with a one-level java.util.Map from paths to non-null values. Null values are
|
||||
* not "in" the map.
|
||||
*/
|
||||
final class SimpleConfig implements Config, MergeableValue {
|
||||
final class SimpleConfig implements Config, MergeableValue, Serializable {
|
||||
|
||||
final private AbstractConfigObject object;
|
||||
|
||||
|
@ -21,7 +21,8 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
|
||||
final private boolean resolved;
|
||||
|
||||
SimpleConfigList(ConfigOrigin origin, List<AbstractConfigValue> value) {
|
||||
this(origin, value, ResolveStatus.fromValues(value));
|
||||
this(origin, value, ResolveStatus
|
||||
.fromValues(value));
|
||||
}
|
||||
|
||||
SimpleConfigList(ConfigOrigin origin, List<AbstractConfigValue> value,
|
||||
|
@ -4,6 +4,7 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
@ -17,7 +18,7 @@ import com.typesafe.config.ConfigOrigin;
|
||||
|
||||
// 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 {
|
||||
final class SimpleConfigOrigin implements ConfigOrigin, Serializable {
|
||||
final private String description;
|
||||
final private int lineNumber;
|
||||
final private int endLineNumber;
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
final class SubstitutionExpression {
|
||||
import java.io.Serializable;
|
||||
|
||||
final class SubstitutionExpression implements Serializable {
|
||||
|
||||
final private Path path;
|
||||
final private boolean optional;
|
||||
|
@ -322,6 +322,11 @@ class ConfigSubstitutionTest extends TestUtils {
|
||||
""")
|
||||
}
|
||||
|
||||
@Test
|
||||
def serializeUnresolvedObject() {
|
||||
checkSerializable(substComplexObject)
|
||||
}
|
||||
|
||||
// this is a weird test, it used to test fallback to system props which made more sense.
|
||||
// Now it just tests that if you override with system props, you can use system props
|
||||
// in substitutions.
|
||||
|
@ -792,6 +792,12 @@ class ConfigTest extends TestUtils {
|
||||
assertEquals(None, entries.get("nulls.null"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def test01Serializable() {
|
||||
val conf = ConfigFactory.load("test01")
|
||||
val confCopy = checkSerializable(conf)
|
||||
}
|
||||
|
||||
@Test
|
||||
def test02SubstitutionsWithWeirdPaths() {
|
||||
val conf = ConfigFactory.load("test02")
|
||||
|
@ -28,6 +28,12 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(a, b)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configOriginSerializable() {
|
||||
val a = SimpleConfigOrigin.newSimple("foo")
|
||||
checkSerializable(a)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configIntEquality() {
|
||||
val a = intValue(42)
|
||||
@ -39,6 +45,13 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(a, b)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configIntSerializable() {
|
||||
val a = intValue(42)
|
||||
val b = checkSerializable(a)
|
||||
assertEquals(42, b.unwrapped)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configLongEquality() {
|
||||
val a = longValue(Integer.MAX_VALUE + 42L)
|
||||
@ -104,6 +117,16 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(b, b.toConfig())
|
||||
}
|
||||
|
||||
@Test
|
||||
def configObjectSerializable() {
|
||||
val aMap = configMap("a" -> 1, "b" -> 2, "c" -> 3)
|
||||
val a = new SimpleConfigObject(fakeOrigin(), aMap)
|
||||
val b = checkSerializable(a)
|
||||
assertEquals(1, b.toConfig.getInt("a"))
|
||||
// check that deserialized Config and ConfigObject refer to each other
|
||||
assertTrue(b.toConfig.root eq b)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configListEquality() {
|
||||
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
|
||||
@ -117,6 +140,14 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(aList, bList)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configListSerializable() {
|
||||
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
|
||||
val aList = new SimpleConfigList(fakeOrigin(), aScalaSeq.asJava)
|
||||
val bList = checkSerializable(aList)
|
||||
assertEquals(1, bList.get(0).unwrapped())
|
||||
}
|
||||
|
||||
@Test
|
||||
def configSubstitutionEquality() {
|
||||
val a = subst("foo")
|
||||
@ -128,6 +159,12 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(a, b)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configSubstitutionSerializable() {
|
||||
val a = subst("foo")
|
||||
val b = checkSerializable(a)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDelayedMergeEquality() {
|
||||
val s1 = subst("foo")
|
||||
@ -141,6 +178,14 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(a, b)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDelayedMergeSerializable() {
|
||||
val s1 = subst("foo")
|
||||
val s2 = subst("bar")
|
||||
val a = new ConfigDelayedMerge(fakeOrigin(), List[AbstractConfigValue](s1, s2).asJava)
|
||||
val b = checkSerializable(a)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDelayedMergeObjectEquality() {
|
||||
val empty = SimpleConfigObject.empty()
|
||||
@ -155,6 +200,15 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(a, b)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDelayedMergeObjectSerializable() {
|
||||
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(a)
|
||||
}
|
||||
|
||||
@Test
|
||||
def valuesToString() {
|
||||
// just check that these don't throw, the exact output
|
||||
|
@ -13,6 +13,10 @@ import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigSyntax
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import java.io.File
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.ObjectOutputStream
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ObjectInputStream
|
||||
|
||||
abstract trait TestUtils {
|
||||
protected def intercept[E <: Throwable: Manifest](block: => Unit): E = {
|
||||
@ -82,6 +86,44 @@ abstract trait TestUtils {
|
||||
checkNotEqualToRandomOtherThing(b)
|
||||
}
|
||||
|
||||
private def copyViaSerialize(o: java.io.Serializable): AnyRef = {
|
||||
val byteStream = new ByteArrayOutputStream()
|
||||
val objectStream = new ObjectOutputStream(byteStream)
|
||||
objectStream.writeObject(o)
|
||||
objectStream.close()
|
||||
val inStream = new ByteArrayInputStream(byteStream.toByteArray())
|
||||
val inObjectStream = new ObjectInputStream(inStream)
|
||||
val copy = inObjectStream.readObject()
|
||||
inObjectStream.close()
|
||||
copy
|
||||
}
|
||||
|
||||
protected def checkSerializable[T: Manifest](o: T): T = {
|
||||
checkEqualObjects(o, o)
|
||||
|
||||
assertTrue(o.getClass.getSimpleName + " not an instance of Serializable", o.isInstanceOf[java.io.Serializable])
|
||||
|
||||
val a = o.asInstanceOf[java.io.Serializable]
|
||||
|
||||
val b = try {
|
||||
copyViaSerialize(a)
|
||||
} catch {
|
||||
case nf: ClassNotFoundException =>
|
||||
throw new AssertionError("failed to make a copy via serialization, " +
|
||||
"possibly caused by http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6446627",
|
||||
nf)
|
||||
case e: Exception =>
|
||||
throw new AssertionError("failed to make a copy via serialization", e)
|
||||
}
|
||||
|
||||
assertTrue("deserialized type " + b.getClass.getSimpleName + " doesn't match serialized type " + a.getClass.getSimpleName,
|
||||
manifest[T].erasure.isAssignableFrom(b.getClass))
|
||||
|
||||
checkEqualObjects(a, b)
|
||||
|
||||
b.asInstanceOf[T]
|
||||
}
|
||||
|
||||
def fakeOrigin() = {
|
||||
SimpleConfigOrigin.newSimple("fake origin")
|
||||
}
|
||||
@ -372,7 +414,7 @@ abstract trait TestUtils {
|
||||
protected def substInString(ref: String, optional: Boolean): ConfigSubstitution = {
|
||||
import scala.collection.JavaConverters._
|
||||
val path = Path.newPath(ref)
|
||||
val pieces = List("start<", new SubstitutionExpression(path, optional), ">end")
|
||||
val pieces = List[AnyRef]("start<", new SubstitutionExpression(path, optional), ">end")
|
||||
new ConfigSubstitution(fakeOrigin(), pieces.asJava)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user