> ## Documentation Index
> Fetch the complete documentation index at: https://nexus-core.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# DataAddon API Reference

> Full reference for the DataAddon abstract class: all required methods, the handler registry, per-addon validation, and the NexusJsonDataContainer payload type.

The `DataAddon` abstract class is the contract every addon must implement. It declares the required methods that tell Nexus Core how to identify the addon, where to persist data, how to key the cache, and whether to process a given request. All methods are called by the framework; you never invoke them directly from your addon.

## Required Abstract Methods

### `addonId()`

```java theme={null}
public abstract int addonId();
```

Returns the globally unique numeric ID for this addon. Remote clients send this value as the `protocol` field in their packets. Nexus Core uses it to look up the addon in the registry.

<Warning>
  No two registered addons may share the same `addonId()` value. Use a constants class to avoid collisions. See [Best Practices](/addons/best-practices).
</Warning>

### `addonName()`

```java theme={null}
public abstract String addonName();
```

Returns a human-readable name displayed in the dashboard and log output. This value is for observability only and does not affect routing.

### `getDatabase()`

```java theme={null}
public abstract String getDatabase();
```

Returns the name of the database (or schema) this addon reads from and writes to. For MongoDB adapters this is the database name; for SQL adapters (PostgreSQL, MySQL) this is the schema or catalog name.

<Note>
  As of v1.7.0, the persistence layer supports multiple database adapters. `getDatabase()` is interpreted by the active driver for this addon. MongoDB addons using the default data source work without changes.
</Note>

### `getCollection()`

```java theme={null}
public abstract String getCollection();
```

Returns the collection or table name. Nexus Core routes all CRUD operations to this target through the addon's configured database adapter. For MongoDB this is the collection name; for SQL adapters this is the table name.

### `cacheKeyHeaderTag()`

```java theme={null}
public abstract String cacheKeyHeaderTag();
```

Returns the prefix used when constructing Redis cache keys. The full key format is `{tag}_{idFieldValue}`. Use a distinctive, addon-specific prefix to prevent key collisions with other addons.

### `getCacheTTL()`

```java theme={null}
public abstract int getCacheTTL();
```

Returns the time-to-live in seconds for cache entries written by this addon. The value controls both the Caffeine L1 per-entry TTL and the Redis `EX` parameter on every `SET` call. Choosing an appropriate TTL per addon prevents stale data and controls memory consumption in both cache layers.

### `l1CacheEnabled()`

```java theme={null}
public boolean l1CacheEnabled();
```

Controls whether the Caffeine L1 in-memory cache is used for this addon. The default implementation returns `true`. Override and return `false` to bypass L1 entirely; reads will always pass through to Redis L2 first. Use this for large payloads or rarely-accessed data where holding a deserialized copy in memory is not worth the overhead.

```java theme={null}
@Override
public boolean l1CacheEnabled() {
    return false; // skip L1, always read from Redis L2
}
```

### `handleRequest()`

```java theme={null}
public abstract boolean handleRequest(
    String source,
    RequestType requestType,
    NexusJsonDataContainer data
);
```

Called as a **gate** before any request handler runs. Return `true` to allow dispatch to the registered `RequestHandler`; return `false` to stop processing and discard the request silently.

* `source` — the ID of the Spigot server that sent the packet (e.g. `"pvp-1"`)
* `requestType` — the operation being requested (`GET_DATA`, `SET_DATA`, `REMOVE_DATA`, etc.)
* `data` — the payload container from the incoming packet

<Note>
  `handleRequest()` runs synchronously on the inbound processing thread. Keep it fast: perform only lightweight validation. Never call external APIs, sleep, or query a database inside it.
</Note>

## Handler Registry (New in v1.6.2)

As of v1.6.2, each request type is handled by a registered `RequestHandler` instead of a monolithic method body. Nexus Core calls `addon.dispatch(source, type, data)` after `handleRequest()` returns `true`, routing to the correct handler automatically.

### Default Handlers

`DataAddon` registers the following handlers in its constructor via `registerDefaultHandlers()`:

| RequestType      | Default Handler        |
| ---------------- | ---------------------- |
| `GET_DATA`       | `GetDataHandler`       |
| `SET_DATA`       | `SetDataHandler`       |
| `REMOVE_DATA`    | `RemoveDataHandler`    |
| `INCREMENT_DATA` | `IncrementDataHandler` |
| `RANKING`        | `RankingHandler`       |
| `RANK_FINDER`    | `RankFinderHandler`    |

### `registerHandler()`

```java theme={null}
protected final void registerHandler(RequestType type, RequestHandler handler);
```

Registers or replaces a handler for the given request type. Call this in your subclass constructor (after `super()`) to override a default handler or add support for a new request type.

`RequestHandler` is a functional interface:

```java theme={null}
@FunctionalInterface
public interface RequestHandler {
    void handle(DataAddon addon, String source, NexusJsonDataContainer json);
}
```

**Example — override the default SET\_DATA handler:**

```java theme={null}
public class PlayerStatsAddon extends DataAddon {

    public PlayerStatsAddon() {
        super(); // registers default handlers
        registerHandler(RequestType.SET_DATA, (addon, source, json) -> {
            // Custom write logic — e.g. sanitize or transform the payload first
            json.remove("internalField");
            new SetDataHandler().handle(addon, source, json);
        });
    }

    // ... abstract methods
}
```

### `supportedRequestTypes()`

```java theme={null}
public final Set<RequestType> supportedRequestTypes();
```

Returns the unmodifiable set of `RequestType` values for which a handler is currently registered.

## Per-Addon Validation (New in v1.6.1)

Override `additionalValidators()` to enforce custom message rules for your addon. The validators run after the global security chain (signature, timestamp, nonce) passes, and before `handleRequest()` is called.

```java theme={null}
@Override
protected List<MessageValidator> additionalValidators() {
    return List.of(
        message -> message.containsKey("playerUuid")
            ? ValidationResult.ok()
            : ValidationResult.reject("playerUuid field is required")
    );
}
```

The chain is assembled once (lazily, thread-safely) via `getAdditionalValidationChain()` and reused for every subsequent request. See [Security](/concepts/security) for the full `MessageValidator` interface and `ValidationResult` API.

## NexusJsonDataContainer

`NexusJsonDataContainer` is the payload wrapper used throughout the request pipeline. It holds the fields from the incoming packet's `data` object as a typed key-value map. Key methods:

| Method               | Description                                        |
| -------------------- | -------------------------------------------------- |
| `get(key, Class<T>)` | Read a field, casting to the given type            |
| `set(key, value)`    | Write a field                                      |
| `remove(key)`        | Remove a field (e.g. before signing or publishing) |
| `containsKey(key)`   | Check field presence                               |
| `toFullJson()`       | Serialize to a JSON string                         |

## Complete Example

```java theme={null}
public class PlayerStatsAddon extends DataAddon {

    @DbDataModels(isId = true)
    private String uuid;

    @DbDataModels(defaultValue = "0", isId = false)
    private int kills;

    @DbDataModels(defaultValue = "0", isId = false)
    private int deaths;

    @Override public int    addonId()            { return 100; }
    @Override public String addonName()          { return "Player Stats"; }
    @Override public String getDatabase()        { return "nexus_core_db"; }
    @Override public String getCollection()      { return "player_stats"; }
    @Override public String cacheKeyHeaderTag()  { return "stats"; }
    @Override public int    getCacheTTL()        { return 1800; } // 30 minutes

    @Override
    protected List<MessageValidator> additionalValidators() {
        return List.of(
            msg -> msg.containsKey("uuid")
                ? ValidationResult.ok()
                : ValidationResult.reject("uuid field is required")
        );
    }

    @Override
    public boolean handleRequest(String source, RequestType type,
                                 NexusJsonDataContainer data) {
        // Only allow removals from the admin server
        if (type == RequestType.REMOVE_DATA) {
            return "admin".equals(source);
        }
        return true;
    }
}
```

## Related Topics

* [Annotations Reference](/addons/annotations) — the `@DbDataModels` syntax and supported types
* [Security](/concepts/security) — `MessageValidationChain`, `MessageValidator`, and per-addon validation
* [Best Practices](/addons/best-practices) — ID constants, UUID keys, fast `handleRequest`, and more
* [Request Types](/concepts/request-types) — all `RequestType` values and their semantics


## Related topics

- [DataAddon Overview: Defining Data Schemas in Nexus Core](/addons/overview.md)
- [Nexus Core Changelog](/reference/changelog.md)
- [Annotation Reference: @DbDataModels](/addons/annotations.md)
- [Best Practices for Building Nexus Core Addons](/addons/best-practices.md)
- [Request Lifecycle in Nexus Core](/reference/request-lifecycle.md)
