Mapping file
Each mapping version has its own JSON file. The file is a standard OpenSearch mapping object with three required top-level sections.
Required structure
{
"mappings": {
"dynamic": false,
"_meta": {
"schema_version": 0,
"jeap": {
"collection_fields": ["keywords"]
}
},
"properties": {
"search_item": { ... },
"origin": { ... },
"data": { ... }
}
}
}
dynamic: false is required — the plugin validates its presence. The three sections map to the
responsibilities of the index writer service and the domain service:
| Section | Written by | Purpose |
|---|---|---|
search_item | jEAP Index Writer | Indexing metadata: write timestamp, major and minor version. |
origin | jEAP Index Writer | Reference back to the source business object. |
data | Domain service | Application-defined business fields — this section is mapped to Java. |
Collection fields
OpenSearch has no separate array mapping type: the same field mapping accepts either one value or
an array. Use mappings._meta.jeap.collection_fields to declare fields that the plugin must generate
as java.util.List<T>:
"_meta": {
"schema_version": 0,
"jeap": {
"collection_fields": [
"keywords",
"details.codes",
"cases.tags"
]
}
}
Paths are relative to data.properties, use the JSON snake_case field names, and descend through
properties. A parent collection does not change the cardinality of its children: cases and
cases.tags describe two independent collection fields.
All fields, including fields mapped as nested, are single-valued unless listed in
collection_fields. This allows a nested mapping to generate either a single record or a list of
records. The declaration controls the generated Java type only; OpenSearch mapping and query
semantics remain defined by each field's type.
Declaring an object with sub-properties as a collection produces a build warning because
OpenSearch flattens arrays of objects and loses correlation between sibling values. Use nested
when that correlation must be preserved.
Requiredness, null checks, and non-empty collection checks are not expressed by this metadata.
search_item section (fixed)
"search_item": {
"type": "object",
"properties": {
"upserted_at": { "type": "date", "format": "strict_date_optional_time||epoch_millis" },
"major_version": { "type": "integer" },
"minor_version": { "type": "integer" }
}
}
This section must conform to the bundled IndexTypeMappingDescriptor.schema.json validated by the
plugin.
origin section (fixed)
"origin": {
"type": "object",
"properties": {
"id": { "type": "keyword" },
"version": { "type": "keyword" },
"bp_id": { "type": "keyword" },
"tenant": { "type": "keyword" },
"created": { "type": "date", "format": "strict_date_optional_time||epoch_millis" },
"modified": { "type": "date", "format": "strict_date_optional_time||epoch_millis" },
"reference": { "type": "object", "enabled": false }
}
}
data section (application-defined)
The data section defines the business fields specific to the index type. Field names must be
snake_case — the plugin rejects camelCase names at build time.
"data": {
"type": "object",
"properties": {
"document_id": { "type": "keyword" },
"document_title": { "type": "text" },
"issued_by": {
"type": "object",
"properties": {
"name": { "type": "keyword" },
"office": { "type": "keyword" }
}
},
"created_at": { "type": "date", "format": "strict_date_optional_time||epoch_millis" }
}
}
OpenSearch to Java type mapping
The plugin generates Java records from the data section. object and nested fields with
sub-properties become inner records, declared inside the record of the field they belong to, at
any nesting depth.
| OpenSearch type | Java type |
|---|---|
keyword, text, wildcard, constant_keyword | String |
integer, short, byte | Integer |
long | Long |
float, half_float | Float |
double, scaled_float | Double |
boolean | Boolean |
date | java.time.Instant |
binary | String |
object with no sub-properties | JsonNode |
object with sub-properties | Generated inner record |
nested with no sub-properties | JsonNode |
nested with sub-properties | Generated inner record |
Any type in collection_fields is wrapped in List, for example keyword becomes List<String>
and nested with sub-properties becomes List<generated inner record>.
Fields whose JSON name differs from the Java identifier convention get a @JsonProperty annotation.
For example, document_id → @JsonProperty("document_id") String documentId.
object versus nested
Use nested when object values must retain correlation between their sub-fields in OpenSearch.
Cardinality is independent: list the path in collection_fields for an array, or omit it for one
object. Declaring object for a field that carries an array makes OpenSearch flatten the array and
lose correlation between sibling values; the plugin warns about this combination.
"cases": {
"type": "nested",
"properties": {
"case_reference": { "type": "keyword" },
"control_pattern": {
"type": "object",
"properties": {
"factual_name": { "type": "text" }
}
}
}
}
public record MyTypeDataV1(
List<Cases> cases
) {
public record Cases(
@JsonProperty("case_reference") String caseReference,
@JsonProperty("control_pattern") ControlPattern controlPattern
) {
public record ControlPattern(
@JsonProperty("factual_name") String factualName
) {}
}
}