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


# LinkAdd

A new dependency between two tasks, added to a live project through [`SchedulingChanges.links`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/scheduling-changes.md#links>)`.add`. It has the same fields as [`LinkData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/link-data.md>), but `id` is optional. Create one with `new LinkAdd()` and the fluent `withX` setters.

## Declaration

```java
package org.dhtmlx.plen;

public class LinkAdd extends ValueRecord implements DeepCloneable<LinkAdd>
```

## Constructors

### LinkAdd()

```java
public LinkAdd()
```

Creates an add with `id`, `source`, `target` and `lagUnit` set to `null`, `linkType` set to `LinkType.FS` and `lag` set to `0.0`. `source` and `target` must be set before the add goes to `apply`.

## Fields

| Field | Type | Default | Description |
|---|---|---|---|
| `id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | `null` | Id of the new link. `null` makes `apply` generate one. |
| `source` | `Id` | `null` | Id of the predecessor task. Required. |
| `target` | `Id` | `null` | Id of the successor task. Required. |
| `linkType` | [`LinkType`](<https://docs.dhtmlx.com/planning-engine/java/api/data/link-data.md#linktype>) | `LinkType.FS` | Which end of `source` drives which end of `target`. |
| `lag` | `double` | `0.0` | Working time between the two ends, in `lagUnit`. Must be finite. |
| `lagUnit` | [`TimeUnit`](<https://docs.dhtmlx.com/planning-engine/java/api/data/time-unit.md>) | `null` | Unit of `lag`. `null` uses [`SchedulingConfig.durationUnit`](<https://docs.dhtmlx.com/planning-engine/java/api/data/scheduling-config.md#durationunit>). |

`source`, `target`, `linkType`, `lag` and `lagUnit` mean the same as on [`LinkData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/link-data.md>). That includes what happens when an endpoint names no task.

### id

```java
public Id id = null;
```

A non-null id stores the link under that id. It must not repeat the id of a link already in the project.

With `null`, [`Project#apply`](<https://docs.dhtmlx.com/planning-engine/java/api/project-apply.md>) picks the first free id of the form `$generated_link_1`, `$generated_link_2`, and so on. The new id is listed in [`ApplyReport.effects`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/apply-report.md#effects>)`.generatedLinks`. Later updates and removals of the link need that id.

## Methods

### withId, withSource, withTarget, withLinkType, withLag, withLagUnit

```java
public LinkAdd withId(Id value)
public LinkAdd withSource(Id value)
public LinkAdd withTarget(Id value)
public LinkAdd withLinkType(LinkType value)
public LinkAdd withLag(double value)
public LinkAdd withLagUnit(TimeUnit value)
```

Each setter assigns its field and returns this instance.

**Returns**: this `LinkAdd`.

### deepClone

```java
public LinkAdd deepClone()
```

Returns a new `LinkAdd` with the same field values. `Id`, `LinkType` and `TimeUnit` are immutable, so the copy shares nothing that can change.

**Returns**: a new `LinkAdd`.

### copy

```java
public LinkAdd copy()
```

Returns a shallow copy with the same field values.

**Returns**: a new `LinkAdd`.

### 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 `LinkAdd` instances are equal when all six fields are equal. `toString()` lists the fields, for logging.

## Errors

Each `LinkAdd` is one operation, with the path `links.add[i]`. `apply` doesn't throw for a rejected operation. It lists the operation as a [`RejectedOperation`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/rejected-operation.md>) in [`ApplyReport.rejected`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/apply-report.md#rejected>) and moves on to the next one. An add is rejected when:

| Message | When |
|---|---|
| `duplicate link id` | `id` is non-null and the project already has a link with that id |
| `lag must be finite` | `lag` is `NaN` or infinite |

A `null` `source` or `target` makes `apply` throw `NullPointerException`.

An endpoint that names no task, or names an unscheduled task, doesn't get the operation rejected. See [`ChangeEffects`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/apply-report.md#changeeffects>)`.droppedLinks`.

Link removals run before link adds. So a `LinkAdd` can reuse the id of a link removed in the same change set. See [change sets](<https://docs.dhtmlx.com/planning-engine/java/live-projects/editing-a-project.md#change-sets>).

## Example

Link `design` to `build` in a solved project without giving an id, then read back the generated one:

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

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

    ProjectData data = new ProjectData()
        .withTasks(List.of(
            new TaskData(Id.str("design")).withStartDate(monday).withDuration(2.0),
            new TaskData(Id.str("build")).withStartDate(monday).withDuration(3.0)));

    Project project = new Project();
    SolveOptions options = new SolveOptions();
    project.solve(data, options);

    SchedulingChanges changes = new SchedulingChanges();
    changes.links.add.add(new LinkAdd()
        .withSource(Id.str("design"))
        .withTarget(Id.str("build")));

    ApplyReport report = project.apply(changes);
    System.out.println("new link ids: " + report.effects.generatedLinks);

    ScheduleResult result = project.solve(null, options);
    for (Mutation update : result.updates) {
      System.out.println(update.id + ": " + update.startDate + " - " + update.endDate);
    }
  }
}
```

Output:

```
new link ids: [$generated_link_1]
build: 2026-04-08 08:00 - 2026-04-13 08:00
```

`design` takes Monday and Tuesday, so `build` now starts on Wednesday morning.

## Related

- [`LinkData`](<https://docs.dhtmlx.com/planning-engine/java/api/data/link-data.md>) - the stored link and its fields
- [`LinkUpdate`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/link-update.md>) - editing an existing link
- [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/java/api/changes/apply-report.md>) - generated ids and dropped links
- [Links, constraints and summaries](<https://docs.dhtmlx.com/planning-engine/java/scheduling/links-constraints-summaries.md#link-types-and-lag>) - link types and lag
- [Data Updates](<https://docs.dhtmlx.com/planning-engine/java/live-projects/editing-a-project.md#change-sets>) - change sets and operation order
