1
1
package scala .pickling
2
2
3
+ import java .lang .reflect .Field
4
+
3
5
import scala .reflect .runtime .{universe => ru }
4
6
import ir ._
5
7
@@ -37,7 +39,7 @@ class RuntimePickler(classLoader: ClassLoader, clazz: Class[_])(implicit pf: Pic
37
39
import ru ._
38
40
39
41
sealed abstract class Logic (fir : irs.FieldIR , isEffFinal : Boolean ) {
40
- def run (builder : PBuilder , im : ru.InstanceMirror ): Unit = {
42
+ def run (builder : PBuilder , picklee : Any , im : ru.InstanceMirror ): Unit = {
41
43
val fldMirror = im.reflectField(fir.field.get)
42
44
val fldValue : Any = fldMirror.get
43
45
val fldClass = if (fldValue != null ) fldValue.getClass else null
@@ -83,6 +85,41 @@ class RuntimePickler(classLoader: ClassLoader, clazz: Class[_])(implicit pf: Pic
83
85
}
84
86
}
85
87
88
+ sealed class PrivateJavaFieldLogic (fir : irs.FieldIR , field : Field ) extends Logic (fir, false ) {
89
+ override def run (builder : PBuilder , picklee : Any , im : ru.InstanceMirror ): Unit = {
90
+ field.setAccessible(true )
91
+ val fldValue = field.get(picklee)
92
+ val fldClass = if (fldValue != null ) fldValue.getClass else null
93
+
94
+ // debug(s"pickling field of type: ${fir.tpe.toString}")
95
+ // debug(s"isEffFinal: $isEffFinal")
96
+ // debug(s"field value: $fldValue")
97
+ // debug(s"field class: ${fldClass.getName}")
98
+
99
+ // idea: picklers for all fields could be created and cached once and for all.
100
+ // however, it depends on whether the type of the field is effectively final or not.
101
+ // essentially, we have to emulate the behavior of generated picklers, which make
102
+ // the same decision.
103
+ val fldPickler = SPickler .genPickler(classLoader, fldClass).asInstanceOf [SPickler [Any ]]
104
+ // debug(s"looked up field pickler: $fldPickler")
105
+
106
+ builder.putField(field.getName, b => {
107
+ pickleLogic(fldClass, fldValue, b, fldPickler)
108
+ })
109
+ }
110
+
111
+ def pickleLogic (fldClass : Class [_], fldValue : Any , b : PBuilder , fldPickler : SPickler [Any ]): Unit = {
112
+ pickleInto(fldClass, fldValue, b, fldPickler)
113
+ }
114
+ }
115
+
116
+ final class PrivateEffectivelyFinalJavaFieldLogic (fir : irs.FieldIR , field : Field ) extends PrivateJavaFieldLogic (fir, field) {
117
+ override def pickleLogic (fldClass : Class [_], fldValue : Any , b : PBuilder , fldPickler : SPickler [Any ]): Unit = {
118
+ b.hintStaticallyElidedType()
119
+ pickleInto(fldClass, fldValue, b, fldPickler)
120
+ }
121
+ }
122
+
86
123
// difference to old runtime pickler: create tag based on fieldClass instead of fir.tpe
87
124
def pickleInto (fieldClass : Class [_], fieldValue : Any , builder : PBuilder , pickler : SPickler [Any ]): Unit = {
88
125
val fieldTag = FastTypeTag .mkRaw(fieldClass, mirror)
@@ -95,20 +132,51 @@ class RuntimePickler(classLoader: ClassLoader, clazz: Class[_])(implicit pf: Pic
95
132
new SPickler [Any ] {
96
133
val format : PickleFormat = pf
97
134
98
- val fields : List [Logic ] =
99
- cir.fields.filter(_.hasGetter).map { fir =>
135
+ val fields : List [Logic ] = cir.fields.flatMap { fir =>
136
+ if (fir.hasGetter) {
137
+ // debug(s"pickling field of type ${fir.tpe.key}")
138
+ List (
139
+ if (fir.tpe.typeSymbol.isEffectivelyFinal) new EffectivelyFinalLogic (fir)
140
+ else if (fir.tpe.typeSymbol.asType.isAbstractType) new AbstractLogic (fir)
141
+ else new DefaultLogic (fir)
142
+ )
143
+ } else
144
+ try {
145
+ val javaField = clazz.getDeclaredField(fir.name)
146
+ List (
147
+ if (fir.tpe.typeSymbol.isEffectivelyFinal) new PrivateEffectivelyFinalJavaFieldLogic (fir, javaField)
148
+ else new PrivateJavaFieldLogic (fir, javaField)
149
+ )
150
+ } catch {
151
+ case e : java.lang.NoSuchFieldException => List ()
152
+ }
153
+ }
154
+ /*
155
+ {
156
+ debug(s"cir.fields: ${cir.fields.mkString(",")}")
157
+
158
+ val regularFields = cir.fields.filter(_.hasGetter)
159
+ debug(s"regular fields with getters: ${regularFields.mkString(",")}")
160
+
161
+ val ctorParamsWithoutGetter =
162
+ clazz.getDeclaredFields().filter(df => regularFields.forall(_.name != df.getName))
163
+ debug(s"ctor params without getters: ${ctorParamsWithoutGetter.mkString(",")}")
164
+
165
+ ctorParamsWithoutGetter.map(cp => new CtorParamLogic(cp)).toList ++ regularFields.map { fir =>
166
+ debug(s"pickling field of type ${fir.tpe.key}")
100
167
if (fir.tpe.typeSymbol.isEffectivelyFinal) new EffectivelyFinalLogic(fir)
101
168
else if (fir.tpe.typeSymbol.asType.isAbstractType) new AbstractLogic(fir)
102
169
else new DefaultLogic(fir)
103
170
}
104
-
171
+ }
172
+ */
105
173
def putFields (picklee : Any , builder : PBuilder ): Unit = {
106
174
val im = mirror.reflect(picklee)
107
- fields.foreach(_.run(builder, im))
175
+ fields.foreach(_.run(builder, picklee, im))
108
176
}
109
177
110
178
def pickle (picklee : Any , builder : PBuilder ): Unit = {
111
- // debug(s"pickling object of type: ${tag.key}")
179
+ debug(s " pickling object of type: ${tag.key}" )
112
180
builder.beginEntry(picklee)
113
181
putFields(picklee, builder)
114
182
builder.endEntry()
0 commit comments