[Canonical page](<https://docs.dhtmlx.com/planning-engine/java/api/json/decode/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Decode

Static methods that turn JSON text, or a tree from [`Json.parse`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json.md#parse>), into the typed records: [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/project-data.md>), [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/solve-options.md>), [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/scheduling-changes.md>) and the rest. Use it to load JSON into the typed API. The class has no instances. It keeps no state between calls, so any thread can call it.

## Declaration

```java
package org.dhtmlx.plen;

public final class Decode {
  public static <T> T fromJson(String json, Class<T> type)
  public static <T> Vec<T> list(String json, Class<T> type)
  public static <T> T fromValue(Object value, Class<T> type)

  public static ProjectData project(Object value)
  public static ProjectOptions projectOptions(Object value)
  public static SolveOptions solveOptions(Object value)
  public static PreviewOptions previewOptions(Object value)
  public static AnalyzeOptions analyzeOptions(Object value)
  public static LevelingOptions levelingOptions(Object value)
  public static SchedulingChanges changes(Object value)
  public static EvaluateOptions evaluateOptions(Object value)
  public static LoadProfileOptions loadProfileOptions(Object value)
  public static SuggestOptions suggestOptions(Object value)
  public static Pool pool(Object value)
  public static Vec<Candidate> candidates(Object value)
  public static Vec<Slot> slots(Object value)
  public static Vec<Requirement> requirements(Object value)
}
```

## Static methods

### fromJson

```java
public static <T> T fromJson(String json, Class<T> type)
```

Parses `json` and decodes the document into a new `type` instance.

| Name | Type | Description |
|---|---|---|
| `json` | `String` | One JSON document. |
| `type` | `Class<T>` | The record class, such as `ProjectData.class`, `SolveOptions.class` or `SchedulingChanges.class`. Any class is accepted. |

**Returns** - a new `T` built from the document.

**Errors**

| Error | When |
|---|---|
| [`InputException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/input-exception.md>), kind `PARSE` | Malformed JSON, a duplicate key, the document `null`, a value of the wrong JSON type, a missing or `null` required field, an unknown key on a strict record. |
| `InputException`, kind `VALIDATION` | An invalid date string, an unknown enum value, `level: true`. |
| `NullPointerException` | `json` is `null`. |

`InputException.path` is `null` for every error `Decode` throws.

### list

```java
public static <T> Vec<T> list(String json, Class<T> type)
```

Parses `json` as a JSON array and decodes each element into a `type` instance. Use it for top-level arrays: candidates, slots, requirements.

| Name | Type | Description |
|---|---|---|
| `json` | `String` | A JSON array. |
| `type` | `Class<T>` | The element class, such as `Candidate.class`. |

**Returns** - a new [`Vec<T>`](<https://docs.dhtmlx.com/planning-engine/java/api/support/vec.md>) in array order.

**Errors** - `InputException` (`PARSE`) when the document isn't an array or an element is `null`, plus every error of [`fromJson`](<https://docs.dhtmlx.com/planning-engine/java/api/json/decode.md#fromjson>).

### fromValue

```java
public static <T> T fromValue(Object value, Class<T> type)
```

Decodes an already parsed tree: `Map<String, Object>`, `List<Object>`, `String`, `Boolean`, `Number` and `null`, as [`Json.parse`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json.md#parse>) returns them. Use it when the payload is part of a larger document parsed once.

| Name | Type | Description |
|---|---|---|
| `value` | `Object` | The tree for one record. Nullable. |
| `type` | `Class<T>` | The record class. |

**Returns** - a new `T`, or `null` when `value` is `null`.

**Errors** - the decoding errors of [`fromJson`](<https://docs.dhtmlx.com/planning-engine/java/api/json/decode.md#fromjson>). There's no syntax check, because the tree is already parsed.

### Typed shortcuts

```java
public static ProjectData project(Object value)
public static SolveOptions solveOptions(Object value)
public static Vec<Candidate> candidates(Object value)
// ... one per type in the declaration
```

Each record shortcut is `fromValue(value, X.class)` for its return type. `candidates`, `slots` and `requirements` take a `List` tree and decode each element, the same way as [`list`](<https://docs.dhtmlx.com/planning-engine/java/api/json/decode.md#list>).

| Method | Returns |
|---|---|
| `project` | [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/project-data.md>) |
| `projectOptions` | [`ProjectOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/project-options.md>) |
| `solveOptions` | [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/solve-options.md>) |
| `previewOptions` | [`PreviewOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/preview-options.md>) |
| `analyzeOptions` | [`AnalyzeOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/analyze-options.md>) |
| `levelingOptions` | [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/leveling-options.md>); `null` for `false` |
| `changes` | [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/scheduling-changes.md>) |
| `evaluateOptions` | [`EvaluateOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/evaluate/evaluate-options.md>) |
| `loadProfileOptions` | [`LoadProfileOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/load-profile-options.md>) |
| `suggestOptions` | [`SuggestOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-options.md>) |
| `pool` | [`Pool`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/pool.md>) |
| `candidates` | `Vec<`[`Candidate`](<https://docs.dhtmlx.com/planning-engine/java/api/evaluate/candidate.md>)`>` |
| `slots` | `Vec<`[`Slot`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/slot.md>)`>` |
| `requirements` | `Vec<`[`Requirement`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/requirement.md>)`>` |

**Errors** - the decoding errors of [`fromJson`](<https://docs.dhtmlx.com/planning-engine/java/api/json/decode.md#fromjson>). The list shortcuts also throw `InputException` (`PARSE`) when `value` isn't a `List` or holds a `null` element.

## Decoding rules

These rules apply to every method above:

- **Keys.** A snake_case key binds to the camelCase field (`start_date` → `startDate`, `calendar_id` → `calendarId`). `type` binds to `taskType` on task records and `linkType` on link records. On data records (`ProjectData`, `TaskData`, `LinkData` and the like) the camelCase key binds too, and unknown keys are ignored, so UI fields such as `text` pass through. Option, change-set and skill records (`SolveOptions`, `SchedulingChanges`, `Changes`, `Candidate`, `Slot`, `Pool`, `Requirement` and the like) accept only their listed keys. Any other key is a `PARSE` error that names the allowed keys.
- **Required fields.** A required field (`tasks` on `ProjectData`, `id` on `TaskData`, `source` and `target` on links, ...) that's missing or `null` is a `PARSE` error.
- **`null` and missing.** `null` on an ordinary field leaves the field's default. On a [`Patch`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/patch.md>) field, `null` decodes to `Patch.nullValue()` (clear) and a missing key stays `Patch.missing()`. A `null` element inside a list, or a `null` map value, is a `PARSE` error.
- **Numbers.** `int` and `long` fields need an integral number. `int` fields accept `0` to `4294967295` and cap values above `Integer.MAX_VALUE` at `Integer.MAX_VALUE`. Ids accept a number or a string.
- **Enums.** Enum values are matched without regard to case, with `-` read as `_` (`"asap"`, `"ASAP"`, `"task-inherited"`). Spellings that are specific to each enum are on its type page.
- **Value checks.** Decoding checks only JSON types, required fields, dates and enum names. Range and cross-field checks such as `priority` in `0..1000` run later, when the record reaches a [`Project`](<https://docs.dhtmlx.com/planning-engine/java/api/project/project.md>) call.

## Example

```java
import org.dhtmlx.plen.*;

public class DecodeProjectJson {
  public static void main(String[] args) throws Exception {
    String data = """
        {
          "tasks": [
            {"id": 1, "text": "Design", "start_date": "2026-03-02", "duration": 3},
            {"id": 2, "text": "Build", "start_date": "2026-03-02", "duration": 5}
          ],
          "links": [{"id": 1, "source": 1, "target": 2, "type": "0"}]
        }
        """;

    ProjectData project = Decode.fromJson(data, ProjectData.class);
    SolveOptions options = Decode.fromJson("{\"includeUnchanged\": true}", SolveOptions.class);

    ScheduleResult result = new Project().solve(project, options);
    for (Mutation m : result.updates) {
      System.out.println(m.id + ": " + m.startDate + " - " + m.endDate);
    }
    // 1: 2026-03-02 00:00 - 2026-03-05 00:00
    // 2: 2026-03-05 00:00 - 2026-03-12 00:00

    try {
      Decode.fromJson("{\"includeUnchanged\": true, \"bogus\": 1}", SolveOptions.class);
    } catch (InputException e) {
      System.out.println(e.kind + ": " + e.getMessage());
      // PARSE: unknown field `bogus`, expected one of `subtree`, `analytics`, `reasons`, `includeUnchanged`
    }
  }
}
```

To return typed results as JSON, use [`Encode.text`](<https://docs.dhtmlx.com/planning-engine/java/api/json/encode.md#text>). For a full request and response round trip, see [Exchange JSON with a client](<https://docs.dhtmlx.com/planning-engine/java/how-to/exchange-json-with-a-client.md>).

## Related

- [`Json`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json.md>) - the parser that produces the trees `fromValue` takes
- [`Encode`](<https://docs.dhtmlx.com/planning-engine/java/api/json/encode.md>) - writes typed results back as JSON
- [`InputException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/input-exception.md>) - thrown for undecodable input
- [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/project-data.md>) - the main record to decode
- [Exchange JSON with a client](<https://docs.dhtmlx.com/planning-engine/java/how-to/exchange-json-with-a-client.md#decode-json-into-typed-records>) - decoding a request into typed records
