Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
lihaoyi committed Jul 11, 2024
1 parent 961c5c7 commit 9c2f1c4
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 57 deletions.
47 changes: 47 additions & 0 deletions upickle/core/src/upickle/core/Config.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package upickle.core

// Common things for derivation
trait Config {
@deprecated("Not used, left for binary compatibility")
def tagName = Annotator.defaultTagKey

/**
* Whether or not `case class` fields with values equal to the default are serialized.
* Defaults to `false`, so such fields are elided.
*/
def serializeDefaults: Boolean = false

/**
* Map the name of Scala `case class` fields to JSON object fields during de-serialization.
* Must be kept in sync with [[objectAttributeKeyWriteMap]]
*/
def objectAttributeKeyReadMap(s: CharSequence): CharSequence = s

/**
* Map the name of JSON object fields to Scala `case class` fields during serialization.
* Must be kept in sync with [[objectAttributeKeyReadMap]]
*/
def objectAttributeKeyWriteMap(s: CharSequence): CharSequence = s

/**
* Map the name of JSON `$type` field values to Scala `case class` type names during
* de-serialization. Must be kept in sync with [[objectTypeKeyWriteMap]]
*/
def objectTypeKeyReadMap(s: CharSequence): CharSequence = s

/**
* Map the name of Scala `case class` type names to JSON `$type` field value during
* serialization. Must be kept in sync with [[objectTypeKeyReadMap]]
*/
def objectTypeKeyWriteMap(s: CharSequence): CharSequence = s

/**
* Whether top-level `Some(t)`s and `None`s are serialized unboxed as `t` or
* `null`, rather than `[t]` or `[]`. This is generally what people expect,
* although it does cause issues where `Some(null)` when serialized and de-serialized
* can become `None`. Can be disabled to use the boxed serialization format
* as 0-or-1-element-arrays, presering round trip-ability at the expense of
* un-intuitiveness and verbosity
*/
def optionsAsNulls: Boolean = true
}
43 changes: 1 addition & 42 deletions upickle/implicits/src/upickle/implicits/MacrosCommon.scala
Original file line number Diff line number Diff line change
@@ -1,48 +1,7 @@
package upickle.implicits

// Common things for derivation
trait MacrosCommon {

/**
* Whether to use the fully-qualified name of `case class`es and `case object`s which
* are part of `sealed trait` hierarchies when serializing them and writing their `$type`
* key. Defaults to `false`, so `$type` key uses the shortest partially-qualified name.
* Can be set to `true` to use their fully-qualified name.
*/
def objectTypeKeyWriteFullyQualified: Boolean = false

/**
* Whether or not to write `case class` keys which match their default values.
* Defaults to `false`, allowing those keys to be omitted. Can be set to `true`
* to always write field values even if they are equal to the default
*/
def serializeDefaults: Boolean = false

/**
* Transform dictionary keys when writing `case class`es when reading. Can
* be overriden to provide custom mappings between Scala field names and JSON
* field names. Needs to be kept in sync with [[objectAttributeKeyWriteMap]]
*
* This customizes the mapping across all `case class`es fields handled by this
* upickle instance. This can be customized on a field-by-field basis using the
* [[upickle.implicits.key]] annotation on the `case class` field
*/
def objectAttributeKeyReadMap(s: CharSequence): CharSequence = s
def objectAttributeKeyWriteMap(s: CharSequence): CharSequence = s

/**
* Transforms the value of the `$type` field when writing `sealed trait`s,
* to allow custom mapping between the `case class` name and the `$type` field
* in the generated JSON. Must be kept in sync with [[objectTypeKeyWriteMap]].
*
* * This customizes the mapping across all `case class`es fields handled by this
* * upickle instance. This can be customized on a per-`sealed trait` basis using the
* * [[upickle.implicits.key]] annotation on the `case class`
*/
def objectTypeKeyReadMap(s: CharSequence): CharSequence = s
def objectTypeKeyWriteMap(s: CharSequence): CharSequence = s

}
trait MacrosCommon extends upickle.core.Config

object MacrosCommon {
def tagKeyFromParents[P](
Expand Down
2 changes: 0 additions & 2 deletions upickle/src/upickle/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,6 @@ trait LegacyApi extends Api with Annotator{
* of the attribute is.
*/
trait AttributeTagged extends Api with Annotator{
@deprecated("Not used, left for binary compatibility")
def tagName = Annotator.defaultTagKey

@deprecated("Not used, left for binary compatibility")
override def annotate[V](rw: Reader[V], key: String, value: String) = annotate(rw, key, value, value)
Expand Down
26 changes: 13 additions & 13 deletions upickleReadme/Readme.scalatex
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@val jvmExampleTests = wd/'upickle/'test/"src-jvm-2"/'upickle/'example/"JvmExampleTests.scala"
@val macroTests = wd/'upickle/'test/'src/'upickle/"MacroTests.scala"

@val optionsAsNullTests = wd/'upickle/'test/"src"/'upickle/'example/"OptionsAsNullTests.scala"
@val boxedOptionsTests = wd/'upickle/'test/"src"/'upickle/'example/"BoxedOptionsTests.scala"


@a(
Expand Down Expand Up @@ -464,25 +464,25 @@
Often, there will be times that you want to customize something on a
project-wide level. uPickle provides hooks in letting you subclass the
@hl.scala{upickle.Api} trait to create your own bundles apart from the
in-built @hl.scala{upickle.default} and @hl.scala{upickle.legacy}. The
in-built @hl.scala{upickle.default} and @hl.scala{upickle.legacy}. These are listed
below in the @code{upickle.core.Config} trait:

@hl.ref(wd / "upickle" / "core" / "src" / "upickle" / "core" / "Config.scala", Seq("trait Config"))

@p The
following example demonstrates how to customize a bundle to
automatically @code{snake_case} all dictionary keys.

@hl.ref(exampleTests, Seq("\"snakeCase\"", ""))

@p
If you are using uPickle to convert JSON from another source into Scala
data structures, you can also configure it to map @hl.scala{Option[T]}s
to @code{null}s when the option is @code{None}:
uPickle by default serializes Scala @code{None}s to JSON @hl.scala{null}s, and @code{Some(t)}s
to unboxed JSON @code{t}s. This is generally what people want, but can cause issues at
some edge cases (e.g. @hl.scala{Some(null)} can round trip and become @hl.scala{None}).
You can use a more verbose serialization which converts Scala @code{None}s to boxed
JSON @hl.scala{[]]}s, and @code{Some(t)}s to boxed JSON @code{[t]}s

@hl.ref(optionsAsNullTests, "object OptionPickler", "// end_ex")

@p
This custom configuration allows you to treat @hl.scala{null}s as
@hl.scala{None}s and anything else as @hl.scala{Some(...)}s. Simply
@hl.scala{import OptionPickler._} instead of the normal uPickle import
throughout your project and you'll have the customized reading/writing
available to you.
@hl.ref(boxedOptionsTests, "object BoxedOptionsPickler", "// end_ex")

@p
You can also use a custom configuration to change how 64-bit @code{Long}s are
Expand Down

0 comments on commit 9c2f1c4

Please sign in to comment.