@@ -23,8 +23,9 @@ import ValueClasses.isDerivedValueClass
2323 * def productArity: Int
2424 * def productPrefix: String
2525 *
26- * Special handling:
27- * protected def readResolve(): AnyRef
26+ * Add to serializable static objects, unless an implementation
27+ * already exists:
28+ * private def writeReplace(): AnyRef
2829 *
2930 * Selectively added to value classes, unless a non-default
3031 * implementation already exists:
@@ -50,8 +51,10 @@ class SyntheticMethods(thisPhase: DenotTransformer) {
5051 def caseSymbols (implicit ctx : Context ): List [Symbol ] = { initSymbols; myCaseSymbols }
5152 def caseModuleSymbols (implicit ctx : Context ): List [Symbol ] = { initSymbols; myCaseModuleSymbols }
5253
53- /** The synthetic methods of the case or value class `clazz`. */
54- def syntheticMethods (clazz : ClassSymbol )(implicit ctx : Context ): List [Tree ] = {
54+ /** If this is a case or value class, return the appropriate additional methods,
55+ * otherwise return nothing.
56+ */
57+ def caseAndValueMethods (clazz : ClassSymbol )(implicit ctx : Context ): List [Tree ] = {
5558 val clazzType = clazz.appliedRef
5659 lazy val accessors =
5760 if (isDerivedValueClass(clazz)) clazz.paramAccessors.take(1 ) // Tail parameters can only be `erased`
@@ -255,12 +258,38 @@ class SyntheticMethods(thisPhase: DenotTransformer) {
255258 */
256259 def canEqualBody (that : Tree ): Tree = that.isInstance(AnnotatedType (clazzType, Annotation (defn.UncheckedAnnot )))
257260
258- symbolsToSynthesize flatMap syntheticDefIfMissing
261+ symbolsToSynthesize. flatMap( syntheticDefIfMissing)
259262 }
260263
261- def addSyntheticMethods (impl : Template )(implicit ctx : Context ): Template =
262- if (ctx.owner.is(Case ) || isDerivedValueClass(ctx.owner))
263- cpy.Template (impl)(body = impl.body ++ syntheticMethods(ctx.owner.asClass))
264+ /** If this is a serializable static object `Foo`, add the method:
265+ *
266+ * private def writeReplace(): AnyRef =
267+ * new scala.runtime.ModuleSerializationProxy(classOf[Foo.type])
268+ *
269+ * unless an implementation already exists, otherwise do nothing.
270+ */
271+ def serializableObjectMethod (clazz : ClassSymbol )(implicit ctx : Context ): List [Tree ] = {
272+ def hasWriteReplace : Boolean =
273+ clazz.membersNamed(nme.writeReplace)
274+ .filterWithPredicate(s => s.signature == Signature (defn.AnyRefType , isJava = false ))
275+ .exists
276+ if (clazz.is(Module ) && clazz.isStatic && clazz.isSerializable && ! hasWriteReplace) {
277+ val writeReplace = ctx.newSymbol(clazz, nme.writeReplace, Method | Private | Synthetic ,
278+ MethodType (Nil , defn.AnyRefType ), coord = clazz.coord).entered.asTerm
279+ List (
280+ DefDef (writeReplace,
281+ _ => New (defn.ModuleSerializationProxyType ,
282+ defn.ModuleSerializationProxyConstructor ,
283+ List (Literal (Constant (clazz.sourceModule.termRef)))))
284+ .withSpan(ctx.owner.span.focus))
285+ }
264286 else
265- impl
287+ Nil
288+ }
289+
290+ def addSyntheticMethods (impl : Template )(implicit ctx : Context ): Template = {
291+ val clazz = ctx.owner.asClass
292+ cpy.Template (impl)(body = serializableObjectMethod(clazz) ::: caseAndValueMethods(clazz) ::: impl.body)
293+ }
294+
266295}
0 commit comments