mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 14:50:23 +08:00
Merge pull request #462 from akornev/master
SerializedConfigValue.writeExternal and readExternal are inconsistent
This commit is contained in:
commit
d0021d1d3b
@ -3,8 +3,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.typesafe.config.impl;
|
package com.typesafe.config.impl;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.Externalizable;
|
import java.io.Externalizable;
|
||||||
@ -465,19 +467,23 @@ class SerializedConfigValue extends AbstractConfigValue implements Externalizabl
|
|||||||
SerializedField code = readCode(in);
|
SerializedField code = readCode(in);
|
||||||
if (code == SerializedField.END_MARKER) {
|
if (code == SerializedField.END_MARKER) {
|
||||||
return;
|
return;
|
||||||
} else if (code == SerializedField.ROOT_VALUE) {
|
}
|
||||||
in.readInt(); // discard length
|
|
||||||
this.value = readValue(in, null /* baseOrigin */);
|
DataInput input = fieldIn(in);
|
||||||
|
if (code == SerializedField.ROOT_VALUE) {
|
||||||
|
this.value = readValue(input, null /* baseOrigin */);
|
||||||
} else if (code == SerializedField.ROOT_WAS_CONFIG) {
|
} else if (code == SerializedField.ROOT_WAS_CONFIG) {
|
||||||
in.readInt(); // discard length
|
this.wasConfig = input.readBoolean();
|
||||||
this.wasConfig = in.readBoolean();
|
|
||||||
} else {
|
|
||||||
// ignore unknown field
|
|
||||||
skipField(in);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataInput fieldIn(ObjectInput in) throws IOException {
|
||||||
|
byte[] bytes = new byte[in.readInt()];
|
||||||
|
in.readFully(bytes);
|
||||||
|
return new DataInputStream(new ByteArrayInputStream(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
private static ConfigException shouldNotBeUsed() {
|
private static ConfigException shouldNotBeUsed() {
|
||||||
return new ConfigException.BugOrBroken(SerializedConfigValue.class.getName()
|
return new ConfigException.BugOrBroken(SerializedConfigValue.class.getName()
|
||||||
+ " should not exist outside of serialization");
|
+ " should not exist outside of serialization");
|
||||||
|
@ -279,6 +279,23 @@ class ConfigValueTest extends TestUtils {
|
|||||||
assertTrue(b.root.toConfig eq b)
|
assertTrue(b.root.toConfig eq b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reproduces the issue <a href=https://github.com/typesafehub/config/issues/461>#461</a>.
|
||||||
|
* <p>
|
||||||
|
* We use a custom de-/serializer that encodes String objects in a JDK-incompatible way. Encoding used here
|
||||||
|
* is rather simplistic: a long indicating the length in bytes (JDK uses a variable length integer) followed
|
||||||
|
* by the string's bytes. Running this test with the original SerializedConfigValue.readExternal()
|
||||||
|
* implementation results in an EOFException thrown during deserialization.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
def configConfigCustomSerializable() {
|
||||||
|
val aMap = configMap("a" -> 1, "b" -> 2, "c" -> 3)
|
||||||
|
val expected = new SimpleConfigObject(fakeOrigin(), aMap).toConfig
|
||||||
|
val actual = checkSerializableWithCustomSerializer(expected)
|
||||||
|
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
def configListEquality() {
|
def configListEquality() {
|
||||||
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
|
val aScalaSeq = Seq(1, 2, 3) map { intValue(_): AbstractConfigValue }
|
||||||
|
@ -16,6 +16,8 @@ import java.io.ObjectOutputStream
|
|||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ObjectInputStream
|
import java.io.ObjectInputStream
|
||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.InputStream
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@ -883,4 +885,32 @@ abstract trait TestUtils {
|
|||||||
deleteRecursive(scratch)
|
deleteRecursive(scratch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected def checkSerializableWithCustomSerializer[T: Manifest](o: T): T = {
|
||||||
|
val byteStream = new ByteArrayOutputStream()
|
||||||
|
val objectStream = new CustomObjectOutputStream(byteStream)
|
||||||
|
objectStream.writeObject(o)
|
||||||
|
objectStream.close()
|
||||||
|
val inStream = new ByteArrayInputStream(byteStream.toByteArray)
|
||||||
|
val inObjectStream = new CustomObjectInputStream(inStream)
|
||||||
|
val copy = inObjectStream.readObject()
|
||||||
|
inObjectStream.close()
|
||||||
|
copy.asInstanceOf[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomObjectOutputStream(out: OutputStream) extends ObjectOutputStream(out) {
|
||||||
|
override def writeUTF(str: String): Unit = {
|
||||||
|
val bytes = str.getBytes
|
||||||
|
writeLong(bytes.length)
|
||||||
|
write(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomObjectInputStream(in: InputStream) extends ObjectInputStream(in) {
|
||||||
|
override def readUTF(): String = {
|
||||||
|
val bytes = new Array[Byte](readLong().toByte)
|
||||||
|
read(bytes)
|
||||||
|
new String(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user