# Jodd JSON

JavaScript Object Notation (aka [JSON](http://json.org/)) is a very popular lightweight data-interchange format. **Jodd JSON** is a lightweight library for (de)serializing Java objects into and from JSON.

Before you say: "Yet another one?", please check what makes **Jodd JSON** unique. The power of the library is its control over the process of serialization and parsing; ease of use and great performances.

### Quick Start <a href="#quick-start" id="quick-start"></a>

Let's see how to serialize:

```java
Book book = new Book();
book.setName("Jodd in Action);
book.setYear(2018);
book.setAuthors(List.of(new Author("Igor")));

String json = JsonSerializer.create()
        .include("authors")
        .serialize(book);
```

The resulting JSON may look like this:

```javascript
{
    "name" : "Jodd In Action",
    "year" : 2018,
    "authors" : [
        { "firstName" : "Igor" }
    ]
}
```

Parse the JSON back to Java:

```java
Book book2 = new JsonParser()
        .parse(json, Book.class);
```

Pretty simple, right? But don't get blinded by the simplicity, **Jodd JSON** is pretty powerful. Did I mention it is one of the fastest JSON frameworks out there?

### Main features

* simple syntax and fluent interface,
* lazy parser that is super fast,
* annotations for better conversion control,
* convenient `JSONObject` and `JSONArray` classes,
* powerful exclusion and inclusion rules,
* serializer definition for types,
* the only library that can handle any number size,
* pretty formatting of the JSON output,
* loose, more forgiving, parsing mode,
* ways to address the keys and values of the Maps
* flexible fine-tuning,
* and more…

### License

The code is released under the `BSD-2-Clause` license. It has a minimal set of dependencies with the same or similarly open license, so you should be able to use it in any project and for any purpose.


# Installation

Tips on how to install Jodd JSON library in your app

**Jodd JSON** is released on Maven Central. You can use the following snippets to add it to your project:

{% tabs %}
{% tab title="Maven" %}

```markup
<dependency>
  <groupId>org.jodd</groupId>
  <artifactId>jodd-json</artifactId>
  <version>x.x.x</version>
</dependency>
```

{% endtab %}

{% tab title="Gradle" %}

```
implementation 'org.jodd:jodd-json:x.x.x'
```

{% endtab %}

{% tab title="Gradl.kt" %}

```kotlin
implementation("org.jodd:jodd-json:x.x.x")
```

{% endtab %}

{% tab title="Scala SBT" %}

```scala
libraryDependencies += "org.jodd" % "jodd-json" % "x.x.x"
```

{% endtab %}

{% tab title="Ivy" %}

```markup
<dependency org="org.jodd" name="jodd-json" rev="x.x.x" />
```

{% endtab %}

{% tab title="Leiningen" %}

```
[org.jodd/jodd-json "x.x.x"]
```

{% endtab %}

{% tab title="Buildr" %}

```
'org.jodd:jodd-json:jar:x.x.x'
```

{% endtab %}
{% endtabs %}

That is all!

### Snapshots

**Jodd JSON** snapshots are published on [Maven Central Snapshot repo](https://oss.sonatype.org/content/repositories/snapshots/org/jodd/jodd-lagarto/).

{% hint style="warning" %}
Snapshots are released manually. Feel free to contact me if you need a new SNAPSHOT release sooner.
{% endhint %}


# Serializer

Create JSONs from Java objects

`JsonSerializer` serializes objects into JSON strings. Create an instance of the serializer, configure it and you're done! You may re-use the `JsonSerializer` instances (i.e. configurations). Let's see more about how serialization works.

### Basic usage

Create the new instance of `JsonSerializer` and pass an object to serialize:

```java
JsonSerializer jsonSerializer = new JsonSerializer();
String json = jsonSerializer.serialize(object);
```

or as a one-liner:

```java
String json = JsonSerializer.create().serialize(object);
```

Thats it! `JsonSerializer` process the target object according to its type. It recognizes arrays, lists, maps, collections, strings, numbers etc. and returns them in a correct JSON format.

If you pass an object, `JsonSerializer` will scan all its properties (defined by getters) and create JSON map from it. Each property of a bean will be also serialized according to its type and so on. Of course, `JsonSerializer` detects circular dependencies (by checking an object's identity).

There is one important default behavior of `JsonSerializer`:

Collections (lists, arrays...) are **not** serialized by default. {: .attn}

This plays well with some 3rd party libraries (like ORM) where collections represent lazy relationships.

#### Path

JSON serialization is recursive: all properties of target bean gets serialized and so on. During the serialization, `JsonSerializer` browse the 'object graph' of given object. Current serialization position is determined by the *path*: a string that consist of dot-separated property names up to the current position.

{% hint style="info" %}
Path is a reference of a property in object's graph.
{% endhint %}

For example, the path may be `user.work.prefix`. This means that we can get its value in Java by calling: `getUser().getWork().getPrefix()` on target object.

### Deep serialization

If you want to serialize everything, including the collections, don't worry! Just set the `deep` flag to `true`:

```java
String json = jsonSerializer.create().deep(true).serialize(object);
```

The object will be fully serialized. If all your use-cases use deep serialization, it's easy to enable it globally in the configuration.

### Class name meta-data

By default, `JsonSerializer` does **not** outputs object's class name. However, sometimes we want to preserve the type of serialized object (especially if we want to parse the JSON string back into object). To do this, just enable this feature:

```java
JsonSerializer.create()
    .setClassMetadataName("class")
    .serialize(object);
```

This feature can be enabled to be default, too.

### JSON Type Serializers

`JsonSerializer` knows to serializes primitives, collections, strings, integers, and various Java types that are commonly used as bean properties. For each type, there is a `TypeJsonSerializer` instance that defines how type is serialized to a JSON.

It is possible to add a custom serializer for a type. We can:

* register custom serializer for a type, so all instances of this type would be registered the same way, or
* we can bind a property path to custom serializer:

```java
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String json = new JsonSerializer()
        .withSerializer("birthdate", new DateJsonSerializer() {
            @Override
            public void serialize(JsonContext jsonContext, Date date) {
                jsonContext.writeString(dateFormat.format(date));
            }
        })
        .serialize(foo);
```

**Jodd JSON** comes with default set of type serializers that should cover all common types and needs. However, don't hesitate to build your own type serializer when needed.

### Pretty JSON

Default JSON output is not human readable as it does not have any line break. There is a pretty version of a serializer that returns beautiful JSON:

```java
JsonSerializer serializer = new PrettyJsonSerializer();
```

or as a one-liner:

```java
JsonSerializer.createPrettyOne()
```

User can control the indentation size and used character.


# Fine-Tuning

So far we have seen that `JsonSerializer` excludes the collections, and that this behavior is controlled by the `deep` flag. There is more sophisticated way on how to configure what to serialize. Serialization process can be fine-tuned: properties can be included and excluded. There are several ways how to do this.

### Include/Exclude methods

By using `include()` and `exclude()` methods we can include and exclude a property referenced by it's path. Let's take the following class as an example:

```java
public class Person {

    private String name;
    private Address home;
    private Address work;
    private List<Phone> phones = new ArrayList<Phone>();

    // ... and getters and setters
}
```

If we serialize this class using default `JsonSerializer` we will get JSON object with 3 keys: `name`, `home` and `work`. Property `phones` is not serialized by default as it is a collection.

We can include `phones` with the following code:

```java
String json = new JsonSerializer
    .include('phones')
    .serialize(object);
```

In the same way we can exclude a property. For example:

```java
String json = new JsonSerializer
    .exclude('work')
    .include('phones')
    .serialize(object);
```

Resulting JSON in this case would also be a map with 3 keys: `name`, `home` and `phones`.

Of course, you can specify nested include/exclude paths, like:

```java
String json = JsonSerializer.create()
    .exclude('work')
    .include('phones')
    .exclude('phones.areaCode')
    .serialize(object);
```

This time we changed how the inner object (`Phone`) is serialized.

Include/exclude paths can contain a *wildcard* (`*`). Wildcard replaces more properties at once. Wildcard can only substitute whole property names, not partials. Here is how it can be used:

```java
String json = new JsonSerializer
    .exclude('*')
    .include('name')
    .serialize(object);
```

Resulting JSON map this time contains just one key: `name`, as all others properties are excluded.

### JSON Annotation

Using include/exclude methods can be cumbersome if done frequently. *Json* provides a way to express these rules using annotation. The `@JSON` annotation marks a property (getter or a field) as *included* by default.

In above example we may say that `Phones` are integral part of a `Person` and that we should always have them serialized. So we can do the following:

```java
public class Person {

    private String name;
    private Address home;
    private Address work;
    @JSON
    private List<Phone> phones = new ArrayList<Phone>();

    // ... getters and setters
}
```

That's it! But wait, that's not all :) *Json* supports two ways how a class can be annotated:

* In the *default* mode, `JSON` annotations simply defines additional properties that have to be included. All other properties, that are not marked with an annotation, are also included according to the rules. This mode is usually used to include collection properties, that are excluded by default.
* In the *strict* mode, `JSON` annotation defines **only** properties that have to be included. All other properties, that are not marked with an annotation, are **not** included, even though they should be according to the rules. Strict mode is enabled by annotating the class with the annotation and setting the `strict` element to `true`:

```java
@JSON(strict = true)
public class Person {

    @JSON
    private String name;
    @JSON
    private Address home;
    private Address work;
    @JSON
    private List<Phone> phones = new ArrayList<Phone>();

    // ... and getters and setters
}
```

Here property `work` is not serialized as it is not annotated and the class is serialized in `strict` mode.

### Custom key names

Furthermore, `JSON` annotation can change the name of the generated keys, e.g.:

```java
public class Person {

    @JSON
    private String name;
    @JSON(name = "home_address")
    private Address home;

    //...
}
```

We have changed the name of the `home` property to `home_address`.

### Custom JSON Annotation

An awesome feature is that it is possible to set custom JSON annotation. If you do not want to use default annotation from **Jodd JSON**, then just create your own annotation and register it. You don't have to copy all annotation fields, just those that you really need.

Custom annotations is a great way how you can integrate *Json* with the existing codebase.

### Excluding types

We can also exclude properties of certain type or that matches certain type name wildcard pattern. Sometimes we need to serialize complex beans that contain properties that are meaningless for the serialization, like streams. We can exclude such properties from getting serialized:

```java
new JsonSerializer()
    .excludeTypes(InputStream.class)
    .serialize(object);
```

This will exclude properties that are of `InputStream` type. We could also add the following rule:

```java
new JsonSerializer()
    .excludeTypes(InputStream.class)
    .excludeTypes("javax.*")
    .serialize(object);
```

where the whole package gets excluded.


# Parser

Read JSONs and create objects

**Jodd JSON** parser reads JSON string and converts it into objects (i.e. object graph). Mapping JSON data to Java objects may be tricky. **Jodd JSON** uses class and property types to map string JSON values into specific Java type. And as a bonus, it is super fast.

### Basic usage

The parser class is `JsonParser`. When no target type is provided, the parser will convert JSON string to Java `Map` and `List`. Like this:

```java
JsonParser jsonParser = new JsonParser();
Map map = jsonParser.parse(
    "{ \"one\" : { \"two\" : 285 }, \"three\" : true}");
```

or as a one-liner:

```java
Map map = JsonParser.create().parse("{ ... }");
```

JSON string here is converted into a `Map` that contains 2 keys. One of the keys (`one`) holds another `Map` instance. As you can see from the example, simple JSON data types are converted into their counter-part Java types. Boolean value is converted to `Boolean`, number is converted to a `Number` or `BigInteger` etc. `JsonParser` finds the best possible type; for example, if number can be stored into an `int` then `Integer` is returned, but if it is a decimal value then `Double` is returned and so on.

Ok, let's now see how to map JSON to types.

### Parsing to types

Let's start with the JSON data:

```javascript
{
    "name" : "Mak",
    "bars" : {
        "123": {"amount" : 12300},
        "456": {"amount" : 45600}
    },
    "inters" : {
        "letterJ" : {"sign" : "J"},
        "letterO" : {"sign" : "O"},
        "letterD" : {"sign" : "D"}
    }
}
```

This data can be mapped to Java type like:

```java
public class User {
    private String name;
    private Map<String, Bar> bars;
    private Map<String, Inter> inters;
    // ...
}
```

Property `name` is a simple property. But `bars` is a `Map` of `Bars`:

```java
public class Bar {
    private Integer amount;
    // ...
}
```

This is no problem for `JsonParser`. It will parse inner JSON maps to `Bar` types, since the *generic* type of the property specifies the map's content type. In the same way `JsonParser` can handle the `inters` map.

```java
JsonParser jsonParser = new JsonParser();
User user = jsonParser.parse(json, User.class);
```

`JsonParser` now converts JSON directly to a target type. Let's remember:

{% hint style="warning" %}
`JsonParser` lookups for type information from the target's property: the property type and generics information.
{% endhint %}

Using this approach, `JsonParser` can parse complex JSON strings into Java object graph, as long it can resolve the type information.

### Define the target type with paths

To introduce some more complexity, let's say that `Inter` is an interface:

```java
public interface Inter {
    public char getSign();
}
```

and one of its implementations is:

```java
public class InterImpl implements Inter {
    protected char sign;

    public char getSign() {
        return sign;
    }
    public void setSign(char sign) {
        this.sign = sign;
    }
}
```

Now, this is something `JsonParser` that can't figure out by looking at the `inters` property types and its generic information. We need to explicitly specify the target type for maps values. As you could guess, we can use a *path* to specify the mapping. But in this case, the path needs to address the values of the map! No problem - by using a special path name `value` we can address all the values of a map:

```java
User user = new JsonParser()
    .map("inters.values", InterImpl.class)
    .parse(json, User.class);
```

Nice! Similar to the `value`, we could specify the key's type, using the path reference `keys`. Look at the following example:

```java
String json = "{\"eee\" : {\"123\" : \"name\"}}";

Map<String, Map<Long, String>> map =
    new JsonParser()
    .map("values.keys", Long.class)
    .parse(json);
```

We changed the key type of the inner map. This is one more thing to remember:

{% hint style="warning" %}
Use `map()` method to map the target type in the result object graph, specified by its path.
{% endhint %}

Now we have a powerful tool that can parse about any JSON to any Java type. Here is another example:

```javascript
  {
    "1": {
      "first": {
        "areaCode": "404"
      },
      "second": {
        "name": "Jodd"
      }
    }
  }
```

Maybe parsed like this:

```java
Map<String, Pair<Phone, Network>> complex = new JsonParser()
    .map("values", Pair.class)
    .map("values.first", Phone.class)
    .map("values.second", Network.class)
    .parse(json);
```

Each value of the returned map is going to be a `Pair` of two different types.

### Alt(ernative) paths

As seen, the path can contain special names like `values` or `keys` to reference *ALL* values of a map or *ALL* keys of a map (or of an array). But you can not change the type of particular map value, since these special paths address *ALL* items.

But there is a solution to this. By enabling the alternative paths with `.useAltPaths()` we are telling `JsonParser` to match paths to current map values! By default, this option is disabled, for performance reasons (there is some penalty because more paths are matched).

With alt paths enabled, you can reference any value on the map, too.

#### Class meta-data name

Sometimes JSON string does contain information about the target type, stored in 'special' key like `class` or `__class`. If you have such JSON or if you have used this option with `JsonSerializer`, you can enable this feature with `JsonParser` as well:

```java
Target target =
    new JsonParser()
    .setClassMetadataName("class")
    .parse(json);
```

Now every JSON map will be scanned for this special key `class` that holds the full class name of the target. But be careful:

{% hint style="warning" %}
Using class metadata name with `JsonParser` has some performance penalty and may introduce a potential security risk.&#x20;
{% endhint %}

Every JSON map first must be converted to a `Map` so we can fetch the class name and then converted to a target class. Because of this double conversion expect performance penalties if using class metadata name.

There are **security risks** using class meta-data. You may expose a security hole in case an untrusted source manages to specify a class that is accessible through class loader and exposes a set of methods and/or fields, access to which opens an actual security hole. Such classes are known as *deserialization gadgets*.

Because of this, use of "default typing" is not encouraged in general, and in particular is recommended against if the source of content is not trusted. Conversely, default typing may be used for processing content in cases where both ends (sender and receiver) are controlled by the same entity.

For additional security control there is a method to whitelist allowed class names wildcards: `allowClass()`. If the class name does not match one of set wildcard patterns, `JsonParser` will throw an exception. To reset the whitelist, use `allowAllClasses()`.

### Type conversion

As for everything in Jodd, `JoddParser` uses powerful `TypeConverter` to convert between strings to real types.

### Value converters

Sometimes data comes in different flavors. For example, `Date` may be specified as a string in `yyyy/MM/dd` format and not as a number of milliseconds. So we need to explicitly convert the string into `Date`. For that, we can use `ValueConverter`:

```java
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");

Person person = new JsonParser()
        .withValueConverter("birthdate", new ValueConverter<String, Date>() {
            public Date convert(String data) {
                try {
                    return dateFormat.parse(data);
                } catch (ParseException pe) {
                    throw new JsonException(pe);
                }
            }
        })
        .parse(json, Person.class);
```

### Loose mode

**Jodd Json** parser consumes only valid JSON strings. If the JSON string is not valid, an exception is thrown with a detailed message of why parsing failed.

But real-world often does not play by the rules ;) Therefore, `JsonParser` may run in so-called *loose* mode, when it can process more:

```java
JsonParser jsonParser = new JsonParser().looseMode(true);
```

Here is what loose mode may handle:

* both single and double quotes are accepted.
* invalid escape characters are just added to the output.
* strings may be unquoted, too.

For example, `JsonParser` in loose mode may parse the following input:

```
{
    key : value,
    'my' : 'hol\\x'
}
```

This JSON is not valid, but it can be parsed, too.

### Lazy mode

Finally, the performance gem. A common scenario is parsing a (big) JSON document only to access a few keys. For these situations, we actually don't need to parse the complete JSON, only the elements that we need.

**Jodd JSON** has a *lazy* mode that provides exactly that feature. It returns the `Map` or the `List` i.e. in the lazy mode, there is no sense to parse to concrete types. The returned object is lazy since the parsing happens only on key retrieval.

This may boost performance a lot (in the explained scenario)! The downside of this approach is that the JSON string is kept in memory while the returned object exists. Please use the lazy mode with care.

```java
JsonParser jsonParser = new JsonParser().lazy(true);
```

or as a one-liner:

```java
JsonParser jsonParser = JsonParser.createLazyOne();
```


# JsonObject and JsonArray

Generic JSON objects

Default object types of parsed JSON inputs are `Map` and `List`. While this can be enough, sometimes you want a more developer-friendly way to navigate the returned object, especially nested values - you keep casting all over the code. **Jodd JSON** comes with two nice classes: `JsonObject` and `JsonArray` that can be used instead of defaults. They are quite convenient to work with JSON structure.

Here is an example of the usage:

```java
JsonObject jo = JsonParser.create().parseAsJsonObject("{ ... }");

Integer i = jo.getInteger("key");
JsonObject child = jo.getJsonObject("child");
JsonArray ja = jo.getJsonArray("arr");
Double d = ja.getDouble(ndx);
```

### Serialization

Both `JsonObject` and `JsonArray` may be used for serialization, too. You can use them to construct the JSON structure and then serialize it as usual.

### Binary values

`JsonObject` is able to read and write binaries i.e. `byte[]`. Of course, JSON format does not support the binary types, hence the input array is encoded to Base64. Similarly,the  Base64 field can be read as binary and convert into the `byte[]`.


# Configuration

**Jodd JSON** serialization and parsing can be configured globally using the static fields.

The global configuration for `JsonSerializer` is defined in `JsonSerializer.Defaults` class. There you can enable some flags and set some values that will be used by default by any new instance of the `JsonSerializer`.

The same thing applies to the `JsonParser`. Its default configuration is in `JsonParser.Defaults`.


# Miscellaneous

More tricks!

### Convert bean to map

Sometimes you may want to convert an object into a map, using the `JsonSerializer` exclude/include rules. This can be done with `BeanSerializer`, in few steps like this:

```java
final Map<String, Object> map = new HashMap<String, Object>();

JsonContext jsonContext = new JsonSerializer().createJsonContext(null);

BeanSerializer beanSerializer = new BeanSerializer(jsonContext, bean) {
    @Override
    protected void onSerializableProperty(
            String propertyName, Class propertyType, Object value) {
        map.put(propertyName, value);
    }
};

beanSerializer.serialize();
```

`BeanSerializer` parse beans and match properties to all include/exclude rules. Resulting map will contain all *included* properties of a bean. Serializing this map or the bean should give exactly the same results!

This may be handy if you have some further filtering options on some bean.

### Use JsonWriter

`JsonWriter` is a simple class that writes JSON to the output. You can use it to construct JSON directly, without serialization:

```java
StringBuilder sb = new StringBuilder();
JsonWriter jsonWriter = new JsonWriter(sb);

jsonWriter.writeOpenObject();
jsonWriter.writeName("one");
jsonWriter.writeNumber(Long.valueOf(123));
jsonWriter.writeComma();
jsonWriter.writeName("two");
jsonWriter.writeString("UberLight");
jsonWriter.writeCloseObject();
```

This can be handy when e.g. you need to wrap your serialized JSON into another simple map. Instead of creating a new `Map` object you can simply use the writer with the JSON result to create the same thing, but faster.


# Contact

Let's keep in touch!

{% hint style="success" %}

## <info@jodd.org>

{% endhint %}


