@@ -15,7 +15,15 @@ limitations under the License.
15
15
*/
16
16
package com .twitter .chill
17
17
18
- import _root_ .java .io .{ByteArrayOutputStream , Externalizable , ObjectInput , ObjectOutput }
18
+ import _root_ .java .io .{
19
+ ByteArrayOutputStream ,
20
+ ByteArrayInputStream ,
21
+ Externalizable ,
22
+ ObjectInput ,
23
+ ObjectOutput ,
24
+ ObjectInputStream ,
25
+ ObjectOutputStream
26
+ }
19
27
20
28
object Externalizer {
21
29
def apply [T ](t : T ): Externalizer [T ] = {
@@ -64,6 +72,28 @@ class Externalizer[T] extends Externalizable {
64
72
// 1 here is 1 thread, since we will likely only serialize once
65
73
private val kpool = KryoPool .withByteArrayOutputStream(1 , kryo)
66
74
75
+ /** Try to round-trip and see if it works without error
76
+ */
77
+ lazy val javaWorks : Boolean = {
78
+ try {
79
+ val baos = new ByteArrayOutputStream ()
80
+ val oos = new ObjectOutputStream (baos)
81
+ oos.writeObject(item)
82
+ val bytes = baos.toByteArray
83
+ val testInput = new ByteArrayInputStream (bytes)
84
+ val ois = new ObjectInputStream (testInput)
85
+ ois.readObject // this may throw
86
+ true
87
+ }
88
+ catch {
89
+ case t : Throwable =>
90
+ Option (System .getenv.get(" CHILL_EXTERNALIZER_DEBUG" ))
91
+ .filter(_.toBoolean)
92
+ .foreach { _ => t.printStackTrace }
93
+ false
94
+ }
95
+ }
96
+
67
97
private def safeToBytes : Option [Array [Byte ]] = {
68
98
try {
69
99
val bytes = kpool.toBytesWithClass(item)
@@ -84,24 +114,36 @@ class Externalizer[T] extends Externalizable {
84
114
85
115
def readExternal (in : ObjectInput ) {
86
116
in.read match {
117
+ case JAVA =>
118
+ item = in.readObject.asInstanceOf [Option [T ]]
87
119
case KRYO =>
88
120
val sz = in.readInt
89
121
val buf = new Array [Byte ](sz)
90
122
in.readFully(buf)
91
123
item = fromBytes(buf)
92
- case JAVA =>
93
- item = in.readObject.asInstanceOf [Option [T ]]
94
124
}
95
125
}
126
+
127
+ protected def writeJava (out : ObjectOutput ): Boolean =
128
+ javaWorks && {
129
+ out.write(JAVA )
130
+ out.writeObject(item)
131
+ true
132
+ }
133
+
134
+ protected def writeKryo (out : ObjectOutput ): Boolean =
135
+ safeToBytes.map { bytes =>
136
+ out.write(KRYO )
137
+ out.writeInt(bytes.size)
138
+ out.write(bytes)
139
+ true
140
+ }.getOrElse(false )
141
+
96
142
def writeExternal (out : ObjectOutput ) {
97
- safeToBytes match {
98
- case Some (bytes) =>
99
- out.write(KRYO )
100
- out.writeInt(bytes.size)
101
- out.write(bytes)
102
- case None =>
103
- out.write(JAVA )
104
- out.writeObject(item)
143
+ writeJava(out) || writeKryo(out) || {
144
+ val inner = item.get
145
+ sys.error(" Neither Java nor Kyro works for class: %s instance: %s\n export CHILL_EXTERNALIZER_DEBUG=true to see both stack traces"
146
+ .format(inner.getClass, inner))
105
147
}
106
148
}
107
149
}
0 commit comments