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


# Project#roster

Reads the accepted state of a [`Project`](<https://docs.dhtmlx.com/planning-engine/java/api/project/project.md>) without skills: scheduled leaf tasks, resources and active assignments, in model order. Source data for a custom [`Slot`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/slot.md>) list for [`suggestAssignments`](<https://docs.dhtmlx.com/planning-engine/java/api/project-suggest-assignments.md>). Needs a solved project with no unsolved edits.

## Signature

```java
public Roster roster()
```

Synchronous and CPU-only. Doesn't change the project. Not synchronized: serialize calls on one instance.

## Returns

A new [`Roster`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/roster.md>).

## Errors

All exceptions are unchecked.

| Error | When |
|---|---|
| [`ProjectException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/project-exception.md>) with `code == ProjectError.NO_BASELINE` | The project is unsolved or has unsolved edits, for example after `apply` |

## Example

Build one slot per scheduled task that has no assignment yet, open to every resource.

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

public class RosterExample {
  public static void main(String[] args) throws Exception {
    Moment monday = Moment.fromYmdHm(2026, 8, 10, 8, 0);
    ProjectData data = new ProjectData()
        .withTasks(List.of(
            new TaskData(Id.str("a")).withStartDate(monday).withDuration(2.0),
            new TaskData(Id.str("b")).withStartDate(monday).withDuration(2.0)))
        .withResources(List.of(
            new ResourceData().withId(Id.str("dev1")),
            new ResourceData().withId(Id.str("dev2"))))
        .withAssignments(List.of(
            new AssignmentData().withId(Id.str("x")).withTask(Id.str("a")).withResource(Id.str("dev1")).withValue(1.0)));

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

    Roster roster = project.roster();
    List<Slot> slots = roster.tasks.stream()
        .filter(task -> roster.assignments.stream().noneMatch(a -> a.task.equals(task)))
        .map(task -> new Slot(Id.str("slot-" + task), task, roster.resources))
        .collect(Collectors.toList());

    SuggestResult result = project.suggestAssignments(slots, new SuggestOptions());
    System.out.println(slots.size() + " slot(s), " + result.steps.size() + " step(s)");
    // 1 slot(s), 1 step(s)
  }
}
```

## Related

- [`Roster`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/roster.md>) - the tasks, resources and assignments it returns
- [`Slot`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/slot.md>) - slots built from a roster
- [`Project#suggestAssignments`](<https://docs.dhtmlx.com/planning-engine/java/api/project-suggest-assignments.md>) - fills the slots
- [`SkillLayer.slots`](<https://docs.dhtmlx.com/planning-engine/java/api/skill-layer-slots.md>) - builds slots from skills on top of the roster
- [Skills and requirements](<https://docs.dhtmlx.com/planning-engine/java/resources-and-assignment/skills-and-requirements.md>) - the skill layer that reads the roster
