//////////////////////////////////////////

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing,
  software distributed under the License is distributed on an
  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  KIND, either express or implied.  See the License for the
  specific language governing permissions and limitations
  under the License.

//////////////////////////////////////////
ifndef::core-semantics[]
:core-semantics: core-semantics.adoc
endif::[]

= Processing TOML

Groovy has an optional `groovy-toml` module which provides support for converting between Groovy objects and TOML. The classes dedicated to
TOML serialization and parsing are found in the `groovy.toml` package.

[[toml_tomlslurper]]
== TomlSlurper

`TomlSlurper` is a class that parses TOML text or reader content into Groovy data structures (objects) such as maps, lists and
primitive types like `Integer`, `Double`, `Boolean` and `String`.

The class comes with a bunch of overloaded `parse` methods plus some special methods such as `parseText`
and others. For the next example we will use the `parseText` method. It parses a TOML `String` and recursively converts it to a
list or map of objects. The other `parse*` methods are similar in that they return a TOML `String` but for different parameter
types.

[source,groovy]
----
include::../test/groovy/toml/TomlParserTest.groovy[tags=parse_text,indent=0]
----

Notice the result is a plain map and can be handled like a normal Groovy object instance. `TomlSlurper` parses the
given TOML as defined by the https://toml.io/en/v1.0.0-rc.3[Tom's Obvious, Minimal Language].


As `TomlSlurper` is returning pure Groovy object instances without any special TOML classes in the back, its usage
is transparent. In fact, `TomlSlurper` results conform to GPath expressions. GPath is a powerful expression language
that is supported by multiple slurpers for different data formats (`XmlSlurper` for XML being one example).

[NOTE]
For more details please have a look at the section on <<{core-semantics}#gpath_expressions,GPath expressions>>.

The following table gives an overview of the TOML types and the corresponding Groovy data types:

[cols="1,3" options="header"]
|===
|TOML
|Groovy

|string
|`java.lang.String`

|number
|`java.lang.BigDecimal` or `java.lang.Integer`

|object
|`java.util.LinkedHashMap`

|array
|`java.util.ArrayList`

|true
|`true`

|false
|`false`

|null
|`null`

|offset/local date-time, local date, local time
|`java.lang.String` (see the note below)
|===

[NOTE]
Whenever a value in TOML is `null`, `TomlSlurper` supplements it with the Groovy `null` value. This is in contrast to other
TOML parsers that represent a `null` value with a library-provided singleton object.

[NOTE]
====
For the untyped `parse`/`parseText` API, TOML date and time values are returned as
`String`. This is a limitation of the underlying Jackson TOML support, which only
surfaces `java.time.*` types when a target type is supplied. Use the typed
`parseAs`/`parseTextAs` API (see <<toml_typed_temporal>>) for `java.time.LocalDate`,
`java.time.LocalTime`, `java.time.LocalDateTime`, and `java.time.OffsetDateTime`
fidelity.
====

=== Typed parsing

`TomlSlurper` can parse TOML directly into typed objects using Jackson databinding.
Standard Jackson annotations such as `@JsonProperty` and `@JsonFormat` are supported
for property mapping and type conversion:

[source,groovy]
----
include::../test/groovy/toml/TomlParserTest.groovy[tags=typed_class,indent=0]
----

[source,groovy]
----
include::../test/groovy/toml/TomlParserTest.groovy[tags=typed_parsing,indent=0]
----

NOTE: For simple cases, Groovy's `as` coercion also works with the untyped result:
`def config = new TomlSlurper().parseText(toml) as ServerConfig`.
The `parseTextAs` method uses Jackson databinding, which supports richer annotation-driven
mapping via `@JsonProperty`, `@JsonFormat`, etc.

[[toml_typed_temporal]]
=== Typed date and time values

When a target type declares `java.time.*` fields, the typed `parseAs`/`parseTextAs`
API and `TomlBuilder.toToml` round-trip TOML temporal values with full fidelity,
including the original zone offset for `OffsetDateTime`:

[source,groovy]
----
include::../test/groovy/toml/TomlParserTest.groovy[tags=temporal_class,indent=0]
----

[source,groovy]
----
include::../test/groovy/toml/TomlParserTest.groovy[tags=temporal_typed,indent=0]
----

=== Builders

Another way to create TOML from Groovy is to use `TomlBuilder`. The builder provide a
DSL which allows to formulate an object graph which is then converted to TOML.

[source,groovy]
----
include::../test/groovy/toml/TomlBuilderTest.groovy[tags=build_text,indent=0]
----

=== Typed writing

`TomlBuilder.toToml(object)` serializes a typed object directly to TOML using Jackson databinding:

[source,groovy]
----
include::../test/groovy/toml/TomlBuilderTest.groovy[tags=typed_writing,indent=0]
----
