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


# Requirement

A staffing need on one task: `count` workers who satisfy every [`SkillMatch`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/requirement.md#skillmatch>) in `matches`. Create one with `new Requirement(id, task, matches)` and pass a list of requirements to [`SkillLayer.slots`](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md>) together with a [`Pool`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/pool.md>). Each requirement becomes `count` slots.

## Declaration

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

## Constructors

### Requirement(Id, Id, Vec)

```java
public Requirement(Id id, Id task, Vec<SkillMatch> matches)
public Requirement(Id id, Id task, java.util.Collection<? extends SkillMatch> matches)
```

Creates a requirement with `count` 1, `units` 1.0 and `assignments` set to `null`.

| Name | Type | Description |
|---|---|---|
| `id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | Requirement id, unique among the requirements passed to one call. |
| `task` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | The task that needs the workers. |
| `matches` | [`Vec`](<https://docs.dhtmlx.com/planning-engine/java/api/support/vec.md>)`<SkillMatch>` | Skill conditions a worker must meet. |

The `Vec` overload stores the given list itself. The `Collection` overload copies the elements into a new `Vec`, so `List.of(...)` works; `null` stays `null`.

## Fields

| Field | Type | Default | Description |
|---|---|---|---|
| `id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | set by constructor | Requirement id; the base of its slot ids. |
| `task` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | set by constructor | The task the slots belong to. |
| `matches` | [`Vec`](<https://docs.dhtmlx.com/planning-engine/java/api/support/vec.md>)`<SkillMatch>` | set by constructor | Conditions that all must hold for a worker to be allowed. |
| `count` | `int` | `1` | Number of slots, one per worker needed. |
| `units` | `double` | `1.0` | Value of an assignment that fills one of the slots. |
| `assignments` | [`Vec`](<https://docs.dhtmlx.com/planning-engine/java/api/support/vec.md>)`<`[`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>)`>` | `null` | Existing assignments bound to the slots explicitly; `null` = automatic binding. |

[`SkillLayer.slots`](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md>) checks each requirement and throws [`MatchException.Invalid`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/match-exception.md>) with a `requirements[i]…` path when a field is wrong; see [Errors](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md#errors>).

### id

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

Slot ids are `"<id>#<n>"` with `n` from 1 to `count` (see [`SkillLayer.slotId`](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md#skilllayerslotid>)). A slot id becomes the id of the assignment that fills the slot, so an id stays tied to its task: after a commit, reusing it for another task makes the call fail.

### matches

```java
public Vec<SkillMatch> matches = null;
```

A worker is allowed on the slots only when every match holds. An empty list allows every worker in the pool. The field must not be `null` when the requirement is used.

### count

```java
public int count = 1;
```

Must be 1 or more.

### units

```java
public double units = 1.0;
```

Becomes the `value` of each slot, which is the units of the new assignment that fills it. Must be finite and greater than 0.

### assignments

```java
public Vec<Id> assignments = null;
```

With `null`, the task's existing assignments are bound to these slots automatically. A list replaces automatic binding for this requirement: listed assignments take the slots in order, and slots left over stay empty. An empty list leaves all slots empty. An assignment whose id is one of this requirement's slot ids always keeps its slot and must be in the list. The list can't hold more entries than `count`. [`SkillLayer.slots`](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md#binding>) describes binding in full.

## Methods

### withId, withTask, withCount, withUnits

```java
public Requirement withId(Id value)
public Requirement withTask(Id value)
public Requirement withCount(int value)
public Requirement withUnits(double value)
```

Set the field and return this requirement.

### withMatches, withAssignments

```java
public Requirement withMatches(Vec<SkillMatch> value)
public Requirement withMatches(java.util.Collection<? extends SkillMatch> value)
public Requirement withAssignments(Vec<Id> value)
public Requirement withAssignments(java.util.Collection<? extends Id> value)
```

Set the field and return this requirement. The `Vec` overloads store the given list itself. The `Collection` overloads copy the elements into a new `Vec`; `null` sets the field to `null`.

### deepClone

```java
public Requirement deepClone()
```

Returns a deep copy. The `matches` list, each `SkillMatch` in it and the `assignments` list are copied. Throws `NullPointerException` when `matches` is `null`.

### copy

```java
public Requirement copy()
```

Returns a shallow copy. The copy holds the same `matches` and `assignments` lists as the original.

### equals, hashCode, toString

Inherited from [`ValueRecord`](<https://docs.dhtmlx.com/planning-engine/java/api/support/value-record.md>). Two requirements are equal when all fields are equal; lists compare element by element in order. `toString()` returns `Requirement{id=…, task=…, matches=[…], count=…, units=…, assignments=…}`.

## SkillMatch

One condition on a worker's level in one skill. Create one with the static factories.

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

| Field | Type | Default | Description |
|---|---|---|---|
| `skill` | [`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>) | `null` | The skill to check. |
| `op` | [`SkillOp`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/requirement.md#skillop>) | `SkillOp.AT_LEAST` | How the worker's level compares to `value`. |
| `value` | `double` | `1.0` | The level to compare with. Must be finite. |

`new SkillMatch()` with only `skill` set means "has the skill" (level 1 or more). Each field has a fluent setter: `withSkill`, `withOp`, `withValue`.

### atLeast, noMore, equal

```java
public static SkillMatch atLeast(Id skill, double value)
public static SkillMatch noMore(Id skill, double value)
public static SkillMatch equal(Id skill, double value)
```

Return a match with `op` set to `AT_LEAST`, `NO_MORE` or `EQUAL`.

### holds

```java
public boolean holds(Worker worker)
```

Returns `true` when the [`Worker`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/worker.md>)'s level in `skill` satisfies `op` and `value`. A skill the worker doesn't list counts as level 0.

### deepClone, copy

```java
public SkillMatch deepClone()
public SkillMatch copy()
```

Return a copy. `SkillMatch` holds no lists, so both copies are independent of the original.

## SkillOp

The comparison a [`SkillMatch`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/requirement.md#skillmatch>) applies. All three are inclusive.

```java
public enum SkillOp
```

| Value | Description |
|---|---|
| `AT_LEAST` | Worker level >= `value`. The default. |
| `NO_MORE` | Worker level <= `value`. |
| `EQUAL` | Worker level == `value`. |

## Example

Task `api` needs two backend developers at level 2 or higher who aren't juniors.

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

public class RequirementExample {
  public static void main(String[] args) throws Exception {
    Requirement backend = new Requirement(
        Id.str("api-dev"),
        Id.str("api"),
        List.of(
            SkillMatch.atLeast(Id.str("backend"), 2),
            SkillMatch.noMore(Id.str("junior"), 0)))
        .withCount(2);

    Worker ann = new Worker().withResource(Id.str("ann"))
        .withSkills(List.of(new Skill().withId(Id.str("backend")).withValue(3)));

    boolean allowed = backend.matches.stream().allMatch(m -> m.holds(ann));
    System.out.println(allowed); // true
  }
}
```

Passed to `SkillLayer.slots`, this requirement produces the slots `api-dev#1` and `api-dev#2`.

## Related

- [`SkillLayer.slots`](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md>) - turns requirements into slots
- [`Pool`](<https://docs.dhtmlx.com/planning-engine/java/api/assign/pool.md>) - the workers that requirements are matched against
- [`Slot`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/slot.md>) - the slots a requirement produces
- [`MatchException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/match-exception.md>) - thrown for an invalid requirement
- [Skills and requirements](<https://docs.dhtmlx.com/planning-engine/java/resources-and-assignment/skills-and-requirements.md#requirements-and-matches>) - writing requirements and matches
