docs: Use apidoc directive in serialization-jackson.md (#31001)

This commit is contained in:
Andrei Arlou 2022-01-24 14:27:50 +02:00 committed by GitHub
parent 53548d920d
commit 6c5fa4e61c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 23 deletions

View file

@ -68,16 +68,16 @@ For security reasons it is disallowed to bind the Jackson serializers to
open ended types that might be a target for [serialization gadgets](https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062),
such as:
* `java.lang.Object`
* `java.io.Serializable`
* `java.util.Comparable`.
* @javadoc[java.lang.Object](java.lang.Object)
* @javadoc[java.io.Serializable](java.io.Serializable)
* @javadoc[java.lang.Comparable](java.lang.Comparable).
The deny list of possible serialization gadget classes defined by Jackson databind are checked
and disallowed for deserialization.
@@@ warning
Don't use `@JsonTypeInfo(use = Id.CLASS)` or `ObjectMapper.enableDefaultTyping` since that is a security risk
Don't use @javadoc[@JsonTypeInfo(use = Id.CLASS)](com.fasterxml.jackson.annotation.JsonTypeInfo) or @javadoc[ObjectMapper.enableDefaultTyping](com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping--) since that is a security risk
when using @ref:[polymorphic types](#polymorphic-types).
@@@
@ -109,7 +109,7 @@ That is probably because the class has a constructor with a single parameter, li
Java
: @@snip [SerializationDocTest.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/SerializationDocTest.java) { #one-constructor-param-1 }
That can be solved by adding `@JsonCreator` or `@JsonProperty` annotations:
That can be solved by adding @javadoc[@JsonCreator](com.fasterxml.jackson.annotation.JsonCreator) or @javadoc[@JsonProperty](com.fasterxml.jackson.annotation.JsonProperty) annotations:
Java
: @@snip [SerializationDocTest.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/SerializationDocTest.java) { #one-constructor-param-2 }
@ -128,8 +128,8 @@ The `ParameterNamesModule` is configured with `JsonCreator.Mode.PROPERTIES` as d
### Polymorphic types
A polymorphic type is when a certain base type has multiple alternative implementations. When nested fields or
collections are of polymorphic type the concrete implementations of the type must be listed with `@JsonTypeInfo`
and `@JsonSubTypes` annotations.
collections are of polymorphic type the concrete implementations of the type must be listed with @javadoc[@JsonTypeInfo](com.fasterxml.jackson.annotation.JsonTypeInfo)
and @javadoc[@JsonSubTypes](com.fasterxml.jackson.annotation.JsonSubTypes) annotations.
Example:
@ -156,7 +156,7 @@ when deserializing.
@@@ warning
Don't use `@JsonTypeInfo(use = Id.CLASS)` or `ObjectMapper.enableDefaultTyping` since that is a security risk
Don't use @javadoc[@JsonTypeInfo(use = Id.CLASS)](com.fasterxml.jackson.annotation.JsonTypeInfo) or @javadoc[ObjectMapper.enableDefaultTyping](com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping--) since that is a security risk
when using polymorphic types.
@@@
@ -166,8 +166,8 @@ when using polymorphic types.
### ADT with trait and case object
It's common in Scala to use a sealed trait and case objects to represent enums. If the values are case classes
the `@JsonSubTypes` annotation as described above works, but if the values are case objects it will not.
The annotation requires a `Class` and there is no way to define that in an annotation for a `case object`.
the @javadoc[@JsonSubTypes](com.fasterxml.jackson.annotation.JsonSubTypes) annotation as described above works, but if the values are case objects it will not.
The annotation requires a @javadoc[Class](java.lang.Class) and there is no way to define that in an annotation for a `case object`.
The easiest workaround is to define the case objects as case class without any field.
@ -176,11 +176,11 @@ Alternatively, you can define an intermediate trait for the case object and a cu
Scala
: @@snip [SerializationDocSpec.scala](/akka-serialization-jackson/src/test/scala/doc/akka/serialization/jackson/SerializationDocSpec.scala) { #polymorphism-case-object }
The case object `Unicorn` can't be used in a `@JsonSubTypes` annotation, but its trait can. When serializing the case object we need to know which type tag to use, hence the `@JsonTypeName` annotation on the object. When deserializing, Jackson will only know about the trait variant therefore we need a custom deserializer that returns the case object.
The case object `Unicorn` can't be used in a @javadoc[@JsonSubTypes](com.fasterxml.jackson.annotation.JsonSubTypes) annotation, but its trait can. When serializing the case object we need to know which type tag to use, hence the @javadoc[@JsonTypeName](com.fasterxml.jackson.annotation.JsonTypeName) annotation on the object. When deserializing, Jackson will only know about the trait variant therefore we need a custom deserializer that returns the case object.
On the other hand, if the ADT only has case objects, you can solve it by implementing a custom serialization for the enums. Annotate the `trait` with
`@JsonSerialize` and `@JsonDeserialize` and implement the serialization with `StdSerializer` and
`StdDeserializer`.
@javadoc[@JsonSerialize](com.fasterxml.jackson.databind.annotation.JsonSerialize) and @javadoc[@JsonDeserialize](com.fasterxml.jackson.databind.annotation.JsonDeserialize) and implement the serialization with @javadoc[StdSerializer](com.fasterxml.jackson.databind.ser.std.StdSerializer) and
@javadoc[StdDeserializer](com.fasterxml.jackson.databind.deser.std.StdDeserializer).
Scala
: @@snip [CustomAdtSerializer.scala](/akka-serialization-jackson/src/test/scala/doc/akka/serialization/jackson/CustomAdtSerializer.scala) { #adt-trait-object }
@ -246,7 +246,7 @@ Scala
Java
: @@snip [ItemAdded.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v2b/ItemAdded.java) { #add-mandatory }
To add a new mandatory field we have to use a `JacksonMigration` class and set the default value in the migration code.
To add a new mandatory field we have to use a @apidoc[JacksonMigration] class and set the default value in the migration code.
This is how a migration class would look like for adding a `discount` field:
@ -256,15 +256,15 @@ Scala
Java
: @@snip [ItemAddedMigration.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v2b/ItemAddedMigration.java) { #add-mandatory }
Override the `currentVersion` method to define the version number of the current (latest) version. The first version,
Override the @scala[@scaladoc[currentVersion](akka.serialization.jackson.JacksonMigration#currentVersion:Int)]@java[@javadoc[currentVersion()](akka.serialization.jackson.JacksonMigration#currentVersion())] method to define the version number of the current (latest) version. The first version,
when no migration was used, is always 1. Increase this version number whenever you perform a change that is not
backwards compatible without migration code.
Implement the transformation of the old JSON structure to the new JSON structure in the `transform` method.
The [JsonNode](https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/JsonNode.html)
Implement the transformation of the old JSON structure to the new JSON structure in the @apidoc[transform(fromVersion, jsonNode)](JacksonMigration) {scala="#transform(fromVersion:Int,json:com.fasterxml.jackson.databind.JsonNode):com.fasterxml.jackson.databind.JsonNode" java="#transform(int,com.fasterxml.jackson.databind.JsonNode)"} method.
The @javadoc[JsonNode](com.fasterxml.jackson.databind.JsonNode)
is mutable so you can add and remove fields, or change values. Note that you have to cast to specific sub-classes
such as [ObjectNode](https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/node/ObjectNode.html)
and [ArrayNode](https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/node/ArrayNode.html)
such as @javadoc[ObjectNode](com.fasterxml.jackson.databind.node.ObjectNode)
and @javadoc[ArrayNode](com.fasterxml.jackson.databind.node.ArrayNode)
to get access to mutators.
The migration class must be defined in configuration file:
@ -355,7 +355,7 @@ Scala
Java
: @@snip [OrderPlacedMigration.java](/akka-serialization-jackson/src/test/java/jdoc/akka/serialization/jackson/v2a/OrderPlacedMigration.java) { #rename-class }
Note the override of the `transformClassName` method to define the new class name.
Note the override of the @apidoc[transformClassName(fromVersion, className)](JacksonMigration) {scala="#transformClassName(fromVersion:Int,className:String):String" java="#transformClassName(int,java.lang.String)"} method to define the new class name.
That type of migration must be configured with the old class name as key. The actual class can be removed.
@ -464,7 +464,7 @@ the binding name (for example `jackson-cbor`).
For types that already have an Akka Serializer defined that are embedded in types serialized with Jackson the @apidoc[AkkaSerializationSerializer] and
@apidoc[AkkaSerializationDeserializer] can be used to Akka Serialization for individual fields.
The serializer/deserializer are not enabled automatically. The `@JsonSerialize` and `@JsonDeserialize` annotation needs to be added
The serializer/deserializer are not enabled automatically. The @javadoc[@JsonSerialize](com.fasterxml.jackson.databind.annotation.JsonSerialize) and @javadoc[@JsonDeserialize](com.fasterxml.jackson.databind.annotation.JsonDeserialize) annotation needs to be added
to the fields containing the types to be serialized with Akka Serialization.
The type will be embedded as an object with the fields:
@ -477,7 +477,7 @@ The type will be embedded as an object with the fields:
### Configuration per binding
By default the configuration for the Jackson serializers and their `ObjectMapper`s is defined in
By default the configuration for the Jackson serializers and their @javadoc[ObjectMapper](com.fasterxml.jackson.databind.ObjectMapper)s is defined in
the `akka.serialization.jackson` section. It is possible to override that configuration in a more
specific `akka.serialization.jackson.<binding name>` section.
@ -526,7 +526,7 @@ Jackson are used aside from the the following that are changed in Akka's default
### Date/time format
`WRITE_DATES_AS_TIMESTAMPS` and `WRITE_DURATIONS_AS_TIMESTAMPS` are by default disabled, which means that date/time fields are serialized in
@javadoc[WRITE_DATES_AS_TIMESTAMPS](com.fasterxml.jackson.databind.SerializationFeature#WRITE_DATES_AS_TIMESTAMPS) and @javadoc[WRITE_DURATIONS_AS_TIMESTAMPS](com.fasterxml.jackson.databind.SerializationFeature#WRITE_DURATIONS_AS_TIMESTAMPS) are by default disabled, which means that date/time fields are serialized in
ISO-8601 (rfc3339) `yyyy-MM-dd'T'HH:mm:ss.SSSZ` format instead of numeric arrays. This is better for
interoperability but it is slower. If you don't need the ISO format for interoperability with external systems
you can change the following configuration for better performance of date/time fields.

View file

@ -35,6 +35,10 @@ object Paradox {
"javadoc.akka.link_style" -> "direct",
"javadoc.akka.http.base_url" -> "https://doc.akka.io/japi/akka-http/current",
"javadoc.akka.http.link_style" -> "frames",
"javadoc.com.fasterxml.jackson.annotation.base_url" -> "https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-annotations/latest/",
"javadoc.com.fasterxml.jackson.annotation.link_style" -> "direct",
"javadoc.com.fasterxml.jackson.databind.base_url" -> "https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/latest/",
"javadoc.com.fasterxml.jackson.databind.link_style" -> "direct",
"scala.version" -> scalaVersion.value,
"scala.binary.version" -> scalaBinaryVersion.value,
"akka.version" -> version.value,