FasterXML / jackson-core

Core part of Jackson that defines Streaming API as well as basic shared abstractions
Apache License 2.0
2.26k stars 792 forks source link

Enhance pretty printing API to allow custom formatting in serializers #260

Closed bgorven closed 8 years ago

bgorven commented 8 years ago

This is related to https://github.com/mangstadt/ez-vcard/pull/48. I would like to be able to serialize JCards as

[
  "vcard",
  [
    [ "version", { }, "text", "4.0" ],
    [ "prodid", { }, "text", "ez-vcard 0.9.10-SNAPSHOT" ],
    [ "fn", { }, "text", "John Doe" ],
    [ "n", { }, "text", [ "Doe", "john", "", "", "" ] ],
    [ "org", { }, "text", "Acme Solutions" ],
    [ "tel", { "type" : "CELL" }, "text", "+96123456789" ],
    [ "note", { }, "text", "" ]
  ]
]

The PrettyPrinter interface doesn't have any methods to change the format of arrays or objects at generation time, so the only way I was able to get this to work was by creating a DefaultPrettyPrinter, setting it to the JsonGenerator, and switching out the DefaultPrettyPrinter.Indenter at the start and end of each property (see https://github.com/mangstadt/ez-vcard/pull/48/commits/63822e5d2260d3f95f932bf0777923836e6482b0). This only works when the JsonGenerator is entirely controlled by ezvcard code (i.e. when serializing VCards directly to json), and wouldn't work when an embedded VCard is serialized using a custom JsonSerializer.

I'm willing to write the code for any changes, but first I wanted to ask what the design should look like, because presumably whatever changes may be made to support this would affect anyone downstream who may have written a PrettyPrinter implementation.

My suggestion would be to add methods setInlineObjects(boolean) and setInlineArrays(boolean) to the PrettyPrinter interface. Implementations could choose to ignore them, but for DefaultPrettyPrinter, that could be used to change the indentation style for objects and arrays, respectively.

cowtowncoder commented 8 years ago

I am not sure why I follow why PrettyPrinter would not work here: it gets all the necessary callbacks, so wouldn't your implementation be able to keep track of state changes to use whatever indentation you deem necessary?

bgorven commented 8 years ago

The pretty printer doesn't know anything about the structure of the object that is being serialized. So if I wanted to serialize the array the makes up the jcard body with newlines, but serialize each jcard property array inline, there would need to be some way of letting the pretty printer know which type of array it was currently serializing.

cowtowncoder commented 8 years ago

@bgorven It does not directly know, but if needs to, it has to keep state. It also has access to JsonGenerator, which has knowledge of at least JSON structure (via getOutputContext()) as well as (with newer versions) even likely current value object at binding level (via getCurrentValue() which delegates through output context object).

At this point I do not think I want to add more complexity to PrettyPrinter: if the API is not sufficient it is possible that caller directly uses writeRaw() methods to add indentation similar to how DefaultPrettyPrinter does.

bgorven commented 8 years ago

Looks like that worked. Awesome. Thanks.