# How Ossie Defines and Resolves Relationships Between Logical Datasets in a Semantic Model

> Learn how Ossie defines and resolves relationships between logical datasets. Explore structured maps, bidirectional resolution, and validation for semantic models.

- Repository: [The Apache Software Foundation/ossie](https://github.com/apache/ossie)
- Tags: deep-dive
- Published: 2026-07-26

---

**Ossie defines relationships between logical datasets as structured maps linking source and target entities through column-level criteria, then resolves them bidirectionally via `RelationshipMappingHandler` to validate references, reconstruct join conditions, apply default metadata, and preserve unsupported extensions.**

Apache Ossie represents relationships between logical datasets in a semantic model as explicit objects stored within dataset definitions. These objects describe entity-to-entity links with parallel column mappings, enabling the framework to convert between Ossie's internal format and Salesforce semantic models without data loss. The conversion pipeline relies on constants defined in [`ConverterConstants.java`](https://github.com/apache/ossie/blob/main/ConverterConstants.java) and orchestrated handlers in [`DatasetMappingHandler.java`](https://github.com/apache/ossie/blob/main/DatasetMappingHandler.java) and [`RelationshipMappingHandler.java`](https://github.com/apache/ossie/blob/main/RelationshipMappingHandler.java) to manage these relationships.

## Relationship Constants and Structure in [`ConverterConstants.java`](https://github.com/apache/ossie/blob/main/ConverterConstants.java)

Ossie stores each relationship as a map using standardized keys defined in [`converters/salesforce/src/main/java/org/apache/ossie/converter/ConverterConstants.java`](https://github.com/apache/ossie/blob/main/converters/salesforce/src/main/java/org/apache/ossie/converter/ConverterConstants.java). The `RELATIONSHIPS` key holds the list of Ossie-format relationship objects attached to a dataset, while `SEMANTIC_RELATIONSHIPS` stores the Salesforce-format counterpart.

Each relationship object contains:

- **`FROM` / `TO`** — The API names of the source and target entities.
- **`FROM_COLUMNS` / `TO_COLUMNS`** — Parallel lists of column names participating in the join.
- **`CRITERIA`** — An array of objects with `LEFT_SEMANTIC_FIELD_API_NAME` and `RIGHT_SEMANTIC_FIELD_API_NAME` describing column-to-column mappings.
- **`LEFT_SEMANTIC_DEFINITION_API_NAME` / `RIGHT_SEMANTIC_DEFINITION_API_NAME`** — Salesforce fields holding the `FROM` / `TO` entity names.
- **`CARDINALITY`**, **`IS_ENABLED`**, **`JOIN_TYPE`** — Optional metadata that receives default values when omitted.

The `DatasetMappingHandler`, implemented in [`converters/salesforce/src/main/java/org/apache/ossie/converter/DatasetMappingHandler.java`](https://github.com/apache/ossie/blob/main/converters/salesforce/src/main/java/org/apache/ossie/converter/DatasetMappingHandler.java), creates these relationship objects when converting datasets to the semantic model. Later, the `RelationshipMappingHandler` processes them during bidirectional conversion.

## Resolving Relationships with `RelationshipMappingHandler`

The [`RelationshipMappingHandler.java`](https://github.com/apache/ossie/blob/main/RelationshipMappingHandler.java) file in `converters/salesforce/src/main/java/org/apache/ossie/converter/` serves as the core engine for resolving relationships between logical datasets. It receives a `ConversionDirection` flag and delegates to the appropriate method for the requested transformation.

### Ossie-to-Salesforce Mapping (`mapOsiToSalesforce`)

When converting from Ossie to Salesforce, the handler performs the following steps:

1. **Retrieval** — Fetches the list of OSSIE relationships using the `RELATIONSHIPS` key.
2. **Validation and Filtering** — `validateAndFilterRelationships` checks that referenced entities and columns exist in the target `semanticDataObjects`. Invalid relationships are dropped.
3. **Generic Mapping** — `MappingUtils.filterMappingsByPrefix` isolates relationship-specific rules, then `GenericMappingEngine.applyMappings` converts properties.
4. **Criteria Reconstruction** — `reconstructCriteria` populates the Salesforce `criteria` array from the parallel `FROM_COLUMNS` / `TO_COLUMNS` lists.
5. **Default Application** — `applyDefaults` adds standard values for `CARDINALITY`, `IS_ENABLED`, and `JOIN_TYPE` when these fields are absent.
6. **Extension Restoration** — `customExtensionHandler.restoreCustomExtensionsAtLevel` reattaches any temporarily removed custom extensions.

```java
// Inside mapOsiToSalesforce()
List<Object> osiRelationships = getList(sourceData, RELATIONSHIPS);
Map<String, String> relationshipMappings = MappingUtils.filterMappingsByPrefix(mappings, RELATIONSHIPS);
Map<String, Object> mappedData = GenericMappingEngine.applyMappings(sourceData, relationshipMappings);
outputData.putAll(mappedData);
reconstructCriteria(osiRelationships, sfRelationships); // builds the criteria array
applyDefaults(sfRelationships); // adds CARDINALITY, IS_ENABLED, etc.

```

### Salesforce-to-Ossie Reverse Mapping (`mapSalesforceToOsi`)

For the reverse direction, the handler extracts the `semanticRelationships` array and transforms it back into Ossie's format:

1. **Filtering** — Relationships containing unsupported field types, such as Formula or SemanticField, are separated and stored in the top-level `custom_extensions` via `storeUnsupportedRelationshipsAtModelLevel`.
2. **Criteria Deconstruction** — For supported relationships, `deconstructCriteria` converts the Salesforce `criteria` array back into parallel `FROM_COLUMNS` / `TO_COLUMNS` lists while writing the `FROM` / `TO` entity names.
3. **Unmapped Property Preservation** — `customExtensionHandler.storeUnmappedProperties` saves any Salesforce properties that lack direct Ossie counterparts.

```java
// Inside mapSalesforceToOsi()
List<Object> sfRelationships = getList(sourceData, SEMANTIC_RELATIONSHIPS);
deconstructCriteria(sfRelationships, osiRelationships); // extracts columns
customExtensionHandler.storeUnmappedProperties(...);   // preserves extras

```

### Preserving Unmapped Data in Custom Extensions

During both conversion directions, Ossie ensures no data loss through a **custom extensions** mechanism. Unsupported relationships, formula fields, and unmapped Salesforce properties are stored in a `custom_extensions` block rather than discarded. This design guarantees round-trip fidelity when converting between Ossie's logical datasets and external semantic models.

## Constructing a Relationship in the Ossie Logical Model

Developers can define a relationship between logical datasets by creating a map with the required constant keys and attaching it to the dataset's relationship list. The following example demonstrates an Ossie relationship linking an `Account` entity to a `Contact` entity:

```java
// Example of an OSSIE relationship (source side)
Map<String, Object> rel = new LinkedHashMap<>();
rel.put(ConverterConstants.FROM, "Account");
rel.put(ConverterConstants.TO, "Contact");
rel.put(ConverterConstants.FROM_COLUMNS, List.of("Id"));
rel.put(ConverterConstants.TO_COLUMNS, List.of("AccountId"));
rel.put(ConverterConstants.NAME, "Account_Contact_Rel");

// Add to the dataset's relationship list
List<Object> relationships = new ArrayList<>();
relationships.add(rel);
sourceDataset.put(ConverterConstants.RELATIONSHIPS, relationships);

```

This map structure is the foundation that `RelationshipMappingHandler` transforms during semantic model conversion.

## Summary

- Ossie defines relationships between logical datasets as structured maps using keys from [`ConverterConstants.java`](https://github.com/apache/ossie/blob/main/ConverterConstants.java), linking entities via parallel `FROM_COLUMNS` and `TO_COLUMNS` lists and a `CRITERIA` array.
- The [`RelationshipMappingHandler.java`](https://github.com/apache/ossie/blob/main/RelationshipMappingHandler.java) class resolves these relationships bidirectionally, delegating to `mapOsiToSalesforce` or `mapSalesforceToOsi` based on the `ConversionDirection`.
- Validation occurs through `validateAndFilterRelationships`, which drops invalid references before mapping to ensure target entity and column integrity.
- Criteria are reconstructed with `reconstructCriteria` during Ossie-to-Salesforce conversion and deconstructed with `deconstructCriteria` during the reverse trip.
- Default metadata such as `CARDINALITY`, `IS_ENABLED`, and `JOIN_TYPE` are applied automatically when omitted.
- Unmapped or unsupported properties—including Formula and SemanticField relationships—are preserved in `custom_extensions` to guarantee lossless round-trip conversion.

## Frequently Asked Questions

### What constants does Ossie use to define semantic model relationships?

Ossie defines relationship keys in [`ConverterConstants.java`](https://github.com/apache/ossie/blob/main/ConverterConstants.java), including `RELATIONSHIPS` for the Ossie-format list, `SEMANTIC_RELATIONSHIPS` for the Salesforce-format list, `FROM` / `TO` for entity names, `FROM_COLUMNS` / `TO_COLUMNS` for participating columns, and `CRITERIA` for the column-to-column mapping array. Optional keys such as `CARDINALITY`, `IS_ENABLED`, and `JOIN_TYPE` provide additional join metadata.

### How does `RelationshipMappingHandler` validate relationships during conversion?

During Ossie-to-Salesforce conversion, the handler calls `validateAndFilterRelationships` to verify that every referenced entity and column exists in the target `semanticDataObjects`. Relationships that fail this validation are removed from the mapping process, ensuring only valid semantic links reach the output model.

### What happens to unsupported relationships when converting Salesforce to Ossie?

When `mapSalesforceToOsi` encounters relationships with unsupported field types—such as Formula or SemanticField—it invokes `storeUnsupportedRelationshipsAtModelLevel` to move them into a top-level `custom_extensions` block. This prevents data loss while keeping the core semantic model clean.

### Where does Ossie store default metadata like cardinality and join type?

If optional fields are omitted from the source relationship object, `RelationshipMappingHandler` invokes `applyDefaults` during Ossie-to-Salesforce mapping to populate standard values for `CARDINALITY`, `IS_ENABLED`, and `JOIN_TYPE`. These defaults ensure the resulting semantic model remains complete without requiring explicit input for every metadata field.