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


# JsonProject

A [`Project`](<https://docs.dhtmlx.com/planning-engine/java/api/project/project.md>) behind a string API. Each operation takes JSON text and returns an envelope string, so a server endpoint can pass request bodies in and send the result back unchanged. Create one with [`new JsonProject(optionsJson)`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#jsonprojectstring>), then load data with [`solve`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#solve>).

To mix typed and JSON calls on one project, use the static methods of [`Wire`](<https://docs.dhtmlx.com/planning-engine/java/api/json/wire.md>) on a typed `Project` instead.

## Declaration

```java
package org.dhtmlx.plen;

public final class JsonProject
```

`JsonProject` has no public fields. It isn't `AutoCloseable` and needs no explicit release.

Every operation returns one of two envelopes:

```json
{"ok":true,"result":{...}}
{"error":{"code":null,"kind":"validation","message":"...","path":"tasks[0].start_date"},"ok":false}
```

`error.kind` is `"parse"`, `"validation"` or `"project"`. `code` is the kebab-case [`ProjectError`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/project-exception.md>) for `"project"` and `null` otherwise. `path` is the input path, or `null`. Keys are sorted at every depth. See [Read the envelope](<https://docs.dhtmlx.com/planning-engine/java/how-to/exchange-json-with-a-client.md#read-the-envelope>).

Engine errors never escape the operations as exceptions: a [`PlenException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/plen-exception.md>) becomes an error envelope. Other exceptions propagate. A `null` argument throws `NullPointerException`, except the `data` argument of [`solve`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#solve>) and [`analyze`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#analyze>). Pass `"{}"` for default options. The only member that throws on bad input is the [`JsonProject(String)`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#jsonprojectstring>) constructor.

All methods are synchronous. `JsonProject` isn't synchronized, and `copy()` also updates internal sharing flags on the source. Serialize access to one instance. See [Share a project between threads](<https://docs.dhtmlx.com/planning-engine/java/how-to/share-a-project-between-threads.md>).

## Constructors

### JsonProject()

```java
public JsonProject()
```

Creates an empty, unsolved project with default options and strict validation. Same as `new JsonProject("{}")`.

### JsonProject(String)

```java
public JsonProject(String optionsJson)
```

Creates an empty, unsolved project from [`ProjectOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/project-options.md>) JSON, for example `{"validation":"repair"}`.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `optionsJson` | `String` | `ProjectOptions` as JSON text. `"{}"` uses the defaults. |

**Errors**

- [`JsonProjectException`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project-exception.md>) when `optionsJson` doesn't decode. `getErrorJson()` returns the error envelope and `getError()` the [`InputException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/input-exception.md>).
- `NullPointerException` when `optionsJson` is `null`.

## Methods

Each method below except `copy` runs the typed `Project` method of the same name and wraps its result in an envelope. The linked operation page has the full contract and the error codes.

| Method | Input JSON | Result in the envelope | Operation |
|---|---|---|---|
| `solve(data, options)` | [`ProjectData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/project-data.md>) or `null`, [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/solve-options.md>) | [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/java/api/results/schedule-result.md>) | [`Project#solve`](<https://docs.dhtmlx.com/planning-engine/java/api/project-solve.md>) |
| `preview(changes, options)` | [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/scheduling-changes.md>), [`PreviewOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/preview-options.md>) | `ScheduleResult` | [`Project#preview`](<https://docs.dhtmlx.com/planning-engine/java/api/project-preview.md>) |
| `analyze(data, options)` | `ProjectData` or `null`, [`AnalyzeOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/project/analyze-options.md>) | `ScheduleResult` | [`Project#analyze`](<https://docs.dhtmlx.com/planning-engine/java/api/project-analyze.md>) |
| `apply(changes)` | `SchedulingChanges` | [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/apply-report.md>) | [`Project#apply`](<https://docs.dhtmlx.com/planning-engine/java/api/project-apply.md>) |
| `level(options)` | [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/leveling-options.md>) | [`LevelingResult`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/leveling-result.md>) | [`Project#level`](<https://docs.dhtmlx.com/planning-engine/java/api/project-level.md>) |
| `loadProfile(options)` | [`LoadProfileOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/load-profile-options.md>) | [`LoadProfile`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/load-profile.md>) | [`Project#loadProfile`](<https://docs.dhtmlx.com/planning-engine/java/api/project-load-profile.md>) |
| `evaluate(candidates, options)` | array of [`Candidate`](<https://docs.dhtmlx.com/planning-engine/java/api/evaluate/candidate.md>), [`EvaluateOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/evaluate/evaluate-options.md>) | [`EvaluateResult`](<https://docs.dhtmlx.com/planning-engine/java/api/evaluate/evaluate-result.md>) | [`Project#evaluate`](<https://docs.dhtmlx.com/planning-engine/java/api/project-evaluate.md>) |
| `slots(pool, requirements)` | [`Pool`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/pool.md>), array of [`Requirement`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/requirement.md>) | array of [`Slot`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/slot.md>) | [`SkillLayer.slots`](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md>) |
| `suggestAssignments(slots, options)` | array of `Slot`, [`SuggestOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-options.md>) | [`SuggestResult`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-result.md>) | [`Project#suggestAssignments`](<https://docs.dhtmlx.com/planning-engine/java/api/project-suggest-assignments.md>) |

Input JSON that doesn't decode gives an error envelope with `kind` `"parse"`: bad syntax, duplicate keys, a wrong type, a missing required field, a JSON `null` document, or an unknown key in call options or in the change set's own keys.

### solve

```java
public String solve(String data, String options)
```

Schedules the project and accepts the scheduled dates as the baseline. `data` replaces the project's data. `null` reschedules the current state, for example after [`apply`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#apply>).

**Parameters**

| Name | Type | Description |
|---|---|---|
| `data` | `String` | `ProjectData` JSON. Nullable; `null` re-solves the accepted data. |
| `options` | `String` | `SolveOptions` JSON, such as `{"includeUnchanged":true}`. |

**Returns** an envelope with a `ScheduleResult`.

### preview

```java
public String preview(String changes, String options)
```

Schedules a change set on a copy of the solved baseline without keeping it. Needs a solved project; otherwise the envelope has `code` `"no-baseline"`.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `changes` | `String` | `SchedulingChanges` JSON. |
| `options` | `String` | `PreviewOptions` JSON. |

**Returns** an envelope with a `ScheduleResult` for the previewed state.

### analyze

```java
public String analyze(String data, String options)
```

Computes analytics, cycles and overallocations over supplied dates, or over the current dates when `data` is `null`. Doesn't schedule and doesn't install data.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `data` | `String` | `ProjectData` JSON. Nullable; `null` analyzes the current state. |
| `options` | `String` | `AnalyzeOptions` JSON. |

**Returns** an envelope with a `ScheduleResult`.

### apply

```java
public String apply(String changes)
```

Commits a change set to the accepted state and marks it unsolved. Rejected operations go into the report's `rejected` list, set `needsResync`, and leave the project needing `solve(data, …)` with full data.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `changes` | `String` | `SchedulingChanges` JSON. |

**Returns** an envelope with an `ApplyReport`.

### level

```java
public String level(String options)
```

Solves the current state, resolves resource overallocation and accepts the leveled state as the baseline.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `options` | `String` | `LevelingOptions` JSON. |

**Returns** an envelope with a `LevelingResult`.

### loadProfile

```java
public String loadProfile(String options)
```

Reads per-bucket load and capacity of resources on the solved baseline. Needs a solved project.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `options` | `String` | `LoadProfileOptions` JSON: the query fields (`from`, `to`, ...) at the top level. |

**Returns** an envelope with a `LoadProfile`.

### evaluate

```java
public String evaluate(String candidates, String options)
```

Scores alternative change sets against the solved baseline. Needs a solved project. The project isn't modified.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `candidates` | `String` | JSON array of `Candidate`. A `null` element is a `"parse"` error. |
| `options` | `String` | `EvaluateOptions` JSON. |

**Returns** an envelope with an `EvaluateResult`.

### slots

```java
public String slots(String pool, String requirements)
```

Builds the slots that [`suggestAssignments`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#suggestassignments>) takes from a worker pool and task requirements. Needs a solved project with no unsolved edits. A pool or requirement the skill layer rejects gives an error envelope with `kind` `"validation"`.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `pool` | `String` | `Pool` JSON. |
| `requirements` | `String` | JSON array of `Requirement`. |

**Returns** an envelope with an array of `Slot`.

### suggestAssignments

```java
public String suggestAssignments(String slots, String options)
```

Proposes resources for the slots and returns the proposal as a change set. Needs a solved project. The project isn't modified.

**Parameters**

| Name | Type | Description |
|---|---|---|
| `slots` | `String` | JSON array of `Slot`, as returned by [`slots`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project.md#slots>). |
| `options` | `String` | `SuggestOptions` JSON. |

**Returns** an envelope with a `SuggestResult`.

### copy

```java
public JsonProject copy()
```

Returns an independent `JsonProject` over [`Project#copy()`](<https://docs.dhtmlx.com/planning-engine/java/api/project/project.md#copy>). Changes to the copy don't reach the source. Use it to try `apply` or `level` before committing them.

## Example

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

public class JsonProjectExample {
  public static void main(String[] args) throws Exception {
    var project = new JsonProject("{\"validation\":\"repair\"}");

    String data =
        """
        {
          "tasks": [
            {"id": "a", "start_date": "2026-01-05", "duration": 2},
            {"id": "b", "start_date": "2026-01-05", "duration": 1}
          ],
          "links": [{"id": 1, "source": "a", "target": "b", "type": "0"}]
        }
        """;
    System.out.println(project.solve(data, "{\"includeUnchanged\":true}"));

    String changes = "{\"tasks\":{\"update\":[{\"id\":\"a\",\"duration\":3}]}}";
    System.out.println(project.preview(changes, "{}"));

    // Not solved yet: an error envelope, not an exception.
    System.out.println(new JsonProject().preview(changes, "{}"));
  }
}
```

Output (the `baselineId` differs on every run):

```json
{"ok":true,"result":{"baselineId":"1-eb560363f4cab208","conflicts":[],"converged":true,"cycles":[],"notes":[],"updates":[{"duration":2,"end_date":"2026-01-07 00:00","id":"a","kind":"task","start_date":"2026-01-05 00:00"},{"duration":1,"end_date":"2026-01-08 00:00","id":"b","kind":"task","start_date":"2026-01-07 00:00"}]}}
{"ok":true,"result":{"baselineId":"1-eb560363f4cab208","conflicts":[],"converged":true,"cycles":[],"notes":[],"updates":[{"duration":3,"end_date":"2026-01-08 00:00","id":"a","kind":"task","start_date":"2026-01-05 00:00"},{"end_date":"2026-01-09 00:00","id":"b","kind":"task","start_date":"2026-01-08 00:00"}]}}
{"error":{"code":"no-baseline","kind":"project","message":"no-baseline","path":null},"ok":false}
```

## Related

- [`Project`](<https://docs.dhtmlx.com/planning-engine/java/api/project/project.md>) - the typed project behind it
- [`Wire`](<https://docs.dhtmlx.com/planning-engine/java/api/json/wire.md>) - the same operations as static methods on a typed project
- [`JsonProjectException`](<https://docs.dhtmlx.com/planning-engine/java/api/json/json-project-exception.md>) - thrown by the constructor for invalid options
- [Exchange JSON with a client](<https://docs.dhtmlx.com/planning-engine/java/how-to/exchange-json-with-a-client.md#the-jsonproject-methods>) - a full request and response round trip
- [Share a project between threads](<https://docs.dhtmlx.com/planning-engine/java/how-to/share-a-project-between-threads.md>) - serializing access to one instance
