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


# ProjectData

A full project snapshot: scheduling config, calendars, tasks, links, resources and assignments. It's the input of [`Project#solve`](<https://docs.dhtmlx.com/planning-engine/java/api/project-solve.md>), [`Engine.schedule`](<https://docs.dhtmlx.com/planning-engine/java/api/engine-schedule.md>) and [`Project#analyze`](<https://docs.dhtmlx.com/planning-engine/java/api/project-analyze.md>). Create one with `new ProjectData()` and the fluent `withX` setters, or decode JSON with [`Decode.fromJson(json, ProjectData.class)`](<https://docs.dhtmlx.com/planning-engine/java/api/json/decode.md>).

## Declaration

```java
public class ProjectData extends ValueRecord implements DeepCloneable<ProjectData>
```

`ProjectData` is an import format, not stored state. [`Project#solve`](<https://docs.dhtmlx.com/planning-engine/java/api/project-solve.md>) deep-copies it, so later changes to the caller's object don't reach the project.

## Constructors

### ProjectData()

```java
public ProjectData()
```

Creates an empty project: default config and empty lists.

## Fields

| Field | Type | Default | Description |
|---|---|---|---|
| `config` | [`SchedulingConfig`](<https://docs.dhtmlx.com/planning-engine/java/api/data/scheduling-config.md>) | `new SchedulingConfig()` | Project-wide scheduling settings. |
| `calendars` | [`Vec`](<https://docs.dhtmlx.com/planning-engine/java/api/support/vec.md>)`<`[`CalendarData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/calendar-data.md>)`>` | empty | Working calendars. Empty means only the built-in `"global"` calendar: Mon-Fri, 08:00-12:00 and 13:00-17:00. |
| `tasks` | `Vec<`[`TaskData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/task-data.md>)`>` | empty | Tasks, summaries and milestones. |
| `links` | `Vec<`[`LinkData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/link-data.md>)`>` | empty | Dependencies between tasks. |
| `resources` | `Vec<`[`ResourceData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/resource-data.md>)`>` | empty | Resources that assignments book. |
| `assignments` | `Vec<`[`AssignmentData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/assignment-data.md>)`>` | empty | Resource assignments to tasks. |

Every list field holds an empty `Vec` by default. Pass an empty list for "none", not `null`.

## Methods

### withConfig

```java
public ProjectData withConfig(SchedulingConfig value)
```

Sets `config` and returns this instance.

**Returns** - this `ProjectData`.

### withCalendars, withTasks, withLinks, withResources, withAssignments

```java
public ProjectData withCalendars(Vec<CalendarData> value)
public ProjectData withCalendars(java.util.Collection<? extends CalendarData> value)
public ProjectData withTasks(Vec<TaskData> value)
public ProjectData withTasks(java.util.Collection<? extends TaskData> value)
public ProjectData withLinks(Vec<LinkData> value)
public ProjectData withLinks(java.util.Collection<? extends LinkData> value)
public ProjectData withResources(Vec<ResourceData> value)
public ProjectData withResources(java.util.Collection<? extends ResourceData> value)
public ProjectData withAssignments(Vec<AssignmentData> value)
public ProjectData withAssignments(java.util.Collection<? extends AssignmentData> value)
```

Each setter assigns its list and returns this instance. The `Vec` overload stores the given list itself. The `Collection` overload copies the elements into a new `Vec`, so `List.of(...)` works.

**Returns** - this `ProjectData`.

### canonicalizeRoots

```java
public void canonicalizeRoots()
```

Sets `parent` to `null` on every task whose `parent` equals `config.rootId` (default [`Id.num(0.0)`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>)). `Project#solve` calls it on the data it ingests, so callers rarely need it.

### deepClone

```java
public ProjectData deepClone()
```

Returns a copy that shares no list or nested record with this instance.

**Returns** - a new `ProjectData` with the same values.

### copy

```java
public ProjectData copy()
```

Returns a shallow copy. The copy shares `config` and every list with this instance.

**Returns** - a new `ProjectData` with the same field values.

### equals, hashCode, toString

```java
public boolean equals(Object other)
public int hashCode()
public String toString()
```

Inherited from [`ValueRecord`](<https://docs.dhtmlx.com/planning-engine/java/api/support/value-record.md>). Two `ProjectData` are equal when all six fields are equal, lists and nested records compared by value. `toString()` lists the fields.

## Validation

The calls that take a `ProjectData` validate it before scheduling. With strict validation (the default), invalid data throws an [`InputException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/input-exception.md>) whose path names the wire field, for example `tasks[3].constraint_date`. Strict validation rejects:

- duplicate task, link or calendar ids
- a hierarchy cycle in task `parent` values
- a summary with a start and a duration (it takes both dates or neither), or a summary with no dates and no dated children
- a leaf task with fewer than two of start, end and duration, or with all three mutually inconsistent
- a dated constraint without `constraintDate`
- a task `priority` outside 0..1000
- a non-finite link lag
- a calendar with no working time, or `worktime.days` without exactly 7 entries
- `config.maxIterations = 0`, or a negative or non-finite `config.defaultResourceCapacity`

[`Validation.REPAIR`](<https://docs.dhtmlx.com/planning-engine/java/api/project/validation.md>) fixes most of these instead of rejecting them. See [Accept messy input](<https://docs.dhtmlx.com/planning-engine/java/how-to/accept-messy-input.md>).

## Example

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

public class ProjectDataExample {
  public static void main(String[] args) throws Exception {
    Moment monday = Moment.fromYmdHm(2026, 1, 5, 8, 0);

    ProjectData data = new ProjectData()
        .withConfig(new SchedulingConfig().withDurationUnit(TimeUnit.DAY))
        .withTasks(List.of(
            new TaskData(Id.str("design")).withStartDate(monday).withDuration(2.0),
            new TaskData(Id.str("build")).withStartDate(monday).withDuration(3.0)))
        .withLinks(List.of(
            new LinkData().withId(Id.str("l1")).withSource(Id.str("design")).withTarget(Id.str("build"))));

    ScheduleResult result = Engine.schedule(data, new SolveOptions());

    for (Mutation update : result.updates) {
      System.out.println(update.id + ": " + update.startDate + " - " + update.endDate);
    }
  }
}
```

## Related

- [`TaskData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/task-data.md>) - the tasks of a snapshot
- [`SchedulingConfig`](<https://docs.dhtmlx.com/planning-engine/java/api/data/scheduling-config.md>) - project-wide scheduling settings
- [`Project#solve`](<https://docs.dhtmlx.com/planning-engine/java/api/project-solve.md>) - loads a snapshot into a project
- [`Engine.schedule`](<https://docs.dhtmlx.com/planning-engine/java/api/engine-schedule.md>) - schedules a snapshot once
- [Project data](<https://docs.dhtmlx.com/planning-engine/java/scheduling/project-data.md>) - describing tasks, links, dates and config
