diff --git a/skills/cosmosdb-best-practices/rules/model-json-serialization.md b/skills/cosmosdb-best-practices/rules/model-json-serialization.md index de83f83b..5acc4815 100644 --- a/skills/cosmosdb-best-practices/rules/model-json-serialization.md +++ b/skills/cosmosdb-best-practices/rules/model-json-serialization.md @@ -2,7 +2,7 @@ title: Handle JSON serialization correctly for Cosmos DB documents impact: HIGH impactDescription: prevents data loss, null constructor errors, and serialization failures -tags: model, serialization, json, jackson, jsonignore, jsonproperty, bigdecimal +tags: model, serialization, json, jackson, jsonignore, jsonproperty, bigdecimal, jsonignoreproperties, change-feed --- ## Handle JSON Serialization Correctly for Cosmos DB @@ -139,4 +139,36 @@ private Set authorities; Convert between simple and complex types in the service layer, not in the entity. +**Rule 5: Always add `@JsonIgnoreProperties(ignoreUnknown = true)` to entity classes** + +Cosmos DB documents contain system metadata fields (`_rid`, `_self`, `_etag`, `_ts`, `_lsn`) that are not part of your entity model. Without this annotation, Jackson throws `UnrecognizedPropertyException` when deserializing documents — especially during Change Feed processing where these fields are always present: + +``` +com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: + Unrecognized field "_lsn" (class PlayerProfile), not marked as ignorable +``` + +```java +// ❌ Fails on system metadata fields from Cosmos DB +@Container(containerName = "players") +public class PlayerProfile { + @Id + private String id; + private String playerId; + private int score; +} + +// ✅ Ignores unknown fields — safe for Cosmos DB system metadata +@JsonIgnoreProperties(ignoreUnknown = true) +@Container(containerName = "players") +public class PlayerProfile { + @Id + private String id; + private String playerId; + private int score; +} +``` + +This is critical for Change Feed consumers where system metadata fields are always included in the document payload. + Reference: [Jackson annotations guide](https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations) diff --git a/testing-v2/harness/conftest_base.py b/testing-v2/harness/conftest_base.py index 1c1699c5..2d2dbf47 100644 --- a/testing-v2/harness/conftest_base.py +++ b/testing-v2/harness/conftest_base.py @@ -228,7 +228,7 @@ def cosmos_client(): @pytest.fixture(scope="session") def cosmos_database(cosmos_client, iteration_config): """The Cosmos DB database used by the app.""" - db_name = iteration_config.get("database", "gaming-leaderboard-db") + db_name = iteration_config.get("database", "test-db") return cosmos_client.get_database_client(db_name) diff --git a/testing-v2/scenarios/ai-chat-rag/iterations/.gitignore b/testing-v2/scenarios/ai-chat-rag/iterations/.gitignore new file mode 100644 index 00000000..ac29147f --- /dev/null +++ b/testing-v2/scenarios/ai-chat-rag/iterations/.gitignore @@ -0,0 +1,21 @@ +# Build artifacts (per-language) +__pycache__/ +*.pyc +*.pyo +node_modules/ +bin/ +obj/ +target/ +.gradle/ +build/ +dist/ +*.egg-info/ +venv/ +.venv/ + +# Runtime logs and temp files +app-output.log +app-error.log +_start-app.cmd +build-output.log +build-error.log diff --git a/testing-v2/scenarios/ecommerce-order-api/iterations/.gitignore b/testing-v2/scenarios/ecommerce-order-api/iterations/.gitignore new file mode 100644 index 00000000..ac29147f --- /dev/null +++ b/testing-v2/scenarios/ecommerce-order-api/iterations/.gitignore @@ -0,0 +1,21 @@ +# Build artifacts (per-language) +__pycache__/ +*.pyc +*.pyo +node_modules/ +bin/ +obj/ +target/ +.gradle/ +build/ +dist/ +*.egg-info/ +venv/ +.venv/ + +# Runtime logs and temp files +app-output.log +app-error.log +_start-app.cmd +build-output.log +build-error.log diff --git a/testing-v2/scenarios/gaming-leaderboard/iterations/.gitignore b/testing-v2/scenarios/gaming-leaderboard/iterations/.gitignore new file mode 100644 index 00000000..ac29147f --- /dev/null +++ b/testing-v2/scenarios/gaming-leaderboard/iterations/.gitignore @@ -0,0 +1,21 @@ +# Build artifacts (per-language) +__pycache__/ +*.pyc +*.pyo +node_modules/ +bin/ +obj/ +target/ +.gradle/ +build/ +dist/ +*.egg-info/ +venv/ +.venv/ + +# Runtime logs and temp files +app-output.log +app-error.log +_start-app.cmd +build-output.log +build-error.log diff --git a/testing-v2/scenarios/iot-device-telemetry/iterations/.gitignore b/testing-v2/scenarios/iot-device-telemetry/iterations/.gitignore new file mode 100644 index 00000000..ac29147f --- /dev/null +++ b/testing-v2/scenarios/iot-device-telemetry/iterations/.gitignore @@ -0,0 +1,21 @@ +# Build artifacts (per-language) +__pycache__/ +*.pyc +*.pyo +node_modules/ +bin/ +obj/ +target/ +.gradle/ +build/ +dist/ +*.egg-info/ +venv/ +.venv/ + +# Runtime logs and temp files +app-output.log +app-error.log +_start-app.cmd +build-output.log +build-error.log diff --git a/testing-v2/scenarios/multitenant-saas/iterations/.gitignore b/testing-v2/scenarios/multitenant-saas/iterations/.gitignore new file mode 100644 index 00000000..ac29147f --- /dev/null +++ b/testing-v2/scenarios/multitenant-saas/iterations/.gitignore @@ -0,0 +1,21 @@ +# Build artifacts (per-language) +__pycache__/ +*.pyc +*.pyo +node_modules/ +bin/ +obj/ +target/ +.gradle/ +build/ +dist/ +*.egg-info/ +venv/ +.venv/ + +# Runtime logs and temp files +app-output.log +app-error.log +_start-app.cmd +build-output.log +build-error.log