@@ -190,7 +190,7 @@ In order to extend pprint, subclass the PPrinter class and override the `treeify
190
190
For example:
191
191
```kotlin
192
192
class CustomPPrinter1 (val config : PPrinterConfig ) : PPrinter(config) {
193
- override fun treeify (x : Any? , escapeUnicode : Boolean , showFieldNames : Boolean ): Tree =
193
+ override fun treeify (x : Any? , elementName : String? , escapeUnicode : Boolean , showFieldNames : Boolean ): Tree =
194
194
when (x) {
195
195
is java.time.LocalDate -> Tree .Literal (x.format(DateTimeFormatter .ofPattern(" MM/dd/YYYY" )))
196
196
else -> super .treeify(x, escapeUnicode, showFieldNames)
@@ -211,9 +211,9 @@ This printer can then be used as the basis of a custom `pprint`-like user define
211
211
> You can extend it like this :
212
212
> ```kotlin
213
213
> class CustomPPrinter1 <T >(override val serializer : SerializationStrategy <T >, override val config : PPrinterConfig ) : PPrinter<T>(serializer, config) {
214
- > // Overwrite `treeifyWith` instead of treeify
215
- > override fun <R > treeifyWith ( treeifyable : PPrinter . Treeifyable < R >, escapeUnicode : Boolean , showFieldNames : Boolean ): Tree =
216
- > when (val v = treeifyable. value) {
214
+ > // Overwrite `treeifyValueOrNull` in order to handle leaf-types. Note that anything handled here will not be treated as a composite value.
215
+ > override fun <R > treeifyValueOrNull ( value : R , elementName : String? , escapeUnicode : Boolean , showFieldNames : Boolean ): Tree ? =
216
+ > when (value) {
217
217
> is LocalDate -> Tree .Literal (v.format(DateTimeFormatter .ofPattern(" MM/dd/YYYY" )))
218
218
> else -> super .treeifyWith(treeifyable, escapeUnicode, showFieldNames)
219
219
> }
@@ -240,11 +240,14 @@ class MyJavaBean(val a: String, val b: Int) {
240
240
241
241
// Create the custom printer
242
242
class CustomPPrinter2 (val config : PPrinterConfig ) : PPrinter(config) {
243
- override fun treeify (x : Any? , esc : Boolean , names : Boolean ): Tree =
243
+ override fun treeify (x : Any? , elementName : String? , esc : Boolean , names : Boolean ): Tree =
244
244
when (x) {
245
245
// List through the properties of 'MyJavaBean' and recursively call treeify on them.
246
246
// (Note that Tree.Apply takes an iterator of properties so that the interface is lazy)
247
- is MyJavaBean -> Tree .Apply (" MyJavaBean" , listOf (x.getValueA(), x.getValueB()).map { treeify(it, esc, names) }.iterator())
247
+ is MyJavaBean ->
248
+ Tree .Apply (" MyJavaBean" , listOf (x.getValueA() to " A" , x.getValueB() to " B" )
249
+ .map { (field, fieldName) -> treeify(field, fieldName, esc, names) }.iterator()
250
+ )
248
251
else -> super .treeify(x, esc, names)
249
252
}
250
253
}
@@ -258,9 +261,9 @@ println(pp.invoke(bean))
258
261
To print field- names you use Tree .KeyValue :
259
262
```kotlin
260
263
class CustomPPrinter3 (val config : PPrinterConfig ) : PPrinter(config) {
261
- override fun treeify (x : Any? , escapeUnicode : Boolean , showFieldNames : Boolean ): Tree {
264
+ override fun treeify (x : Any? , elementName : String? , escapeUnicode : Boolean , showFieldNames : Boolean ): Tree {
262
265
// function to make recursive calls shorter
263
- fun rec (x : Any? ) = treeify(x, escapeUnicode, showFieldNames)
266
+ fun rec (x : Any? ) = treeify(x, null , escapeUnicode, showFieldNames)
264
267
return when (x) {
265
268
// Recurse on the values, pass result into Tree.KeyValue.
266
269
is MyJavaBean ->
@@ -352,6 +355,77 @@ When using sequences, you will need to annotate the
352
355
sequence- field using `@Serializable(with = PPrintSequenceSerializer ::class )`.
353
356
See the note in the [Infinite Sequences in Kotlin Multiplatform ](#infinite- sequences- in - kotlin- multiplatform) section for more detail.
354
357
358
+ ## Using `elementName` metadata
359
+
360
+ Note that the `elementName` parameter will contain the name of the field of the data class that is being printed.
361
+ You can use this to exclude particular fields. For example:
362
+ ```kotlin
363
+ class CustomPPrinter6 (config : PPrinterConfig ) : PPrinter(config) {
364
+ override fun treeify (x : Any? , elementName : String? , escapeUnicode : Boolean , showFieldNames : Boolean ): Tree =
365
+ when {
366
+ elementName == " born" -> Tree .Literal (" REDACTED" , elementName)
367
+ else -> super .treeify(x, elementName, escapeUnicode, showFieldNames)
368
+ }
369
+ }
370
+
371
+ data class Person (val name : String , val born : LocalDate )
372
+ val pp = CustomPPrinter6 (PPrinterConfig ())
373
+ val joe = Person (" Joe" , LocalDate .of(1981 , 1 , 1 ))
374
+
375
+ println (pp.invoke(joe))
376
+ // > Person(name = "Joe", born = REDACTED)
377
+ ```
378
+
379
+ You can also filter out fields on the parent- element level like this :
380
+ ```kotlin
381
+ data class PersonBorn (val name : String , val born : LocalDate )
382
+
383
+ class CustomPPrinter5 (config : PPrinterConfig ) : PPrinter(config) {
384
+ override fun treeify (x : Any? , elementName : String? , escapeUnicode : Boolean , showFieldNames : Boolean ): Tree =
385
+ when {
386
+ x is PersonBorn ->
387
+ when (val p = super .treeify(x, elementName, escapeUnicode, showFieldNames)) {
388
+ is Tree .Apply -> p.copy(body = p.body.asSequence().toList().filter { it.elementName != " born" }.iterator())
389
+ else -> error(" Expected Tree.Apply" )
390
+ }
391
+ else ->
392
+ super .treeify(x, elementName, escapeUnicode, showFieldNames)
393
+ }
394
+ }
395
+
396
+ val p = PersonBorn (" Joe" , LocalDate .of(1981 , 1 , 1 ))
397
+ println (CustomPPrinter5 (PPrinterConfig ()).invoke(p))
398
+ // > PersonBorn(name = "Joe")
399
+ ```
400
+
401
+ ## Using `elementName` metadata - Kotlin Multiplatform
402
+
403
+ If you want to filter out fields based on `elementName` in Kotlin Multiplatform inside of the PPrinter you need to override
404
+ the `treeifyComposite` method.
405
+ > Since `treeifyValueOrNull` will always be attempted, trying to do super .treeify (or super .treeifyComposite) inside of it will result in a stack- overflow.
406
+
407
+ For example:
408
+ ```kotlin
409
+ @Serializable
410
+ data class PersonBorn (val name : String , val born : Long )
411
+
412
+ class CustomPPrinter6 <T >(override val serializer : SerializationStrategy <T >, override val config : PPrinterConfig ) : PPrinter<T>(serializer, config) {
413
+ override fun <E > treeifyComposite (elem : Treeifyable .Elem <E >, elementName : String? , showFieldNames : Boolean ): Tree =
414
+ when (elem.value) {
415
+ is PersonBorn ->
416
+ when (val p = super .treeifyComposite(elem, elementName, showFieldNames)) {
417
+ is Tree .Apply -> p.copy(body = p.body.asSequence().toList().filter { it.elementName != " born" }.iterator())
418
+ else -> error(" Expected Tree.Apply" )
419
+ }
420
+ else -> super .treeifyComposite(elem, elementName, showFieldNames)
421
+ }
422
+ }
423
+
424
+ val p = PersonBorn (" Joe" , 1234567890 )
425
+ println (CustomPPrinter6 <PersonBorn >(PersonBorn .serializer(), PPrinterConfig ()).invoke(p))
426
+ // > PersonBorn(name = "Joe")
427
+ ```
428
+
355
429
#### Sealed Hierarchies in KMP
356
430
357
431
According to the `kotlinx- serialization` documentation, every member of a sealed hierarchy must be annotated with `@Serializable`.
@@ -388,20 +462,6 @@ class PPrintSequenceSerializer<T>(val element: KSerializer<T>) : KSerializer<Seq
388
462
```
389
463
(Note that a real user- defined serialzier for `Sequence ` will work as well.)
390
464
391
- The actual handling of sequence printing is done in the `treeifyWith` method (roughly) like this :
392
- ```kotlin
393
- open fun <R > treeifyWith (treeifyable : Treeifyable <R >, escapeUnicode : Boolean , showFieldNames : Boolean ): Tree =
394
- when {
395
- treeifyable is Sequence <* > && treeifyable is Treeifyable .Elem && treeifyable.serializer is PPrintSequenceSerializer <* > -> {
396
- @Suppress(" UNCHECKED_CAST" )
397
- val elementSerializer = treeifyable.serializer.element as KSerializer <Any ?>
398
- Tree .Apply (" Sequence" , value.map { treeifyWith(Treeifyable .Elem (it, elementSerializer), escapeUnicode, showFieldNames) }.iterator())
399
- }
400
- else -> super .treeifyWith(treeifyable, escapeUnicode, showFieldNames)
401
- }
402
- ```
403
- You can follow this pattern to define PPrintable serializers for other generic types.
404
-
405
465
#### General Note on Generic ADTs and KMP
406
466
407
467
Due to issues in kotlinx- serialization like [#1341 ](https: // github.com/Kotlin/kotlinx.serialization/issues/1341) there are cases
0 commit comments