Skip to content

feat(postgresql): Add json/jsonb type support to PostgresqlDataTypeFa… - #931

Merged
jeffjensen merged 1 commit into
mainfrom
574-postgresql-json-type
Aug 11, 2026
Merged

jeffjensen merged 1 commit into
mainfrom
574-postgresql-json-type

Conversation

@jeffjensen

@jeffjensen jeffjensen commented Aug 11, 2026

Copy link
Copy Markdown
Member

…ctory

PostgresqlDataTypeFactory had no recognition for PostgreSQL's native json/jsonb columns (reported as sql type OTHER), so they fell through to DefaultDataTypeFactory with no dedicated read/write handling.

Add JsonType, following the same reflection-based PGobject approach as UuidType/InetType/CitextType so dbUnit doesn't need a compile-time dependency on the PostgreSQL driver. One instance handles a single sql type name ("json" or "jsonb") since PostgreSQL has no implicit cast between the two; PostgresqlDataTypeFactory constructs the matching instance per column automatically.

  • Unlike the issue reporter's original 2015 patch attachment, which a prior maintainer reply already flagged as NPEing from setSqlValue() on a null value, this implementation explicitly null-checks in both setSqlValue() (binds sql NULL) and typeCast() (returns null).
  • Add JsonTypeTest (9 cases, including a Mockito-based regression test for the null setSqlValue() path) and 2 new PostgresqlDataTypeFactoryTest cases.
  • Add PostgresqlJsonIT, round-tripping json and jsonb columns (including a null row) through a live PostgreSQL 16 container; jsonb assertions compare parsed document structure since PostgreSQL reformats jsonb text on storage.
  • Document JsonType in databases/postgresql.adoc, cross-linking IsActualEqualToExpectedJsonValueComparer for semantic JSON comparison.

Refs: 574

Claude-Session: https://claude.ai/code/session_017rt6YcFdhBCwafLp6n7mcZ

Summary by Sourcery

Add native PostgreSQL JSON/JSONB column support via a new JsonType and wire it into the PostgreSQL data type factory.

New Features:

  • Introduce JsonType to handle PostgreSQL json and jsonb columns as text values without a compile-time dependency on the PostgreSQL driver.
  • Have PostgresqlDataTypeFactory recognize json and jsonb sql type names (reported as Types.OTHER) and create matching JsonType instances per column.

Documentation:

  • Document JsonType usage and JSON-specific comparison guidance in the PostgreSQL database documentation.

Tests:

  • Add unit tests for JsonType covering constructor behavior, type casting, and null handling in setSqlValue().
  • Add factory tests ensuring PostgresqlDataTypeFactory returns JsonType for json and jsonb columns.
  • Add PostgreSQL integration tests verifying json and jsonb values, including nulls, correctly round-trip through a real database.

Summary by CodeRabbit

  • New Features

    • Added support for PostgreSQL json and jsonb data types.
    • JSON values can be read, inserted, cast, and round-tripped, including NULL values.
    • Preserves the specific PostgreSQL type name during database operations.
  • Documentation

    • Added PostgreSQL JSON/JSONB usage details and guidance for structural JSON comparisons.

@sourcery-ai

sourcery-ai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds dedicated PostgreSQL json/jsonb support via a new JsonType, wires it into PostgresqlDataTypeFactory, and validates behavior with unit, integration, and documentation updates, including correct null handling and json/jsonb-specific behaviors.

Sequence diagram for JsonType.setSqlValue handling json/jsonb

sequenceDiagram
    participant DbUnitClient
    participant JsonType
    participant PreparedStatement
    participant Connection
    participant PGobject

    DbUnitClient->>JsonType: setSqlValue(value, column, statement)
    alt [value is null]
        JsonType->>PreparedStatement: setNull(column, Types.OTHER)
    else [value is not null]
        JsonType->>PreparedStatement: getConnection()
        PreparedStatement-->>JsonType: connection
        JsonType->>JsonType: getJson(value, connection)
        JsonType->>Connection: loadClass(org.postgresql.util.PGobject)
        Connection-->>JsonType: PGobjectClass
        JsonType->>PGobject: new PGobject()
        JsonType->>PGobject: setType(sqlTypeName)
        JsonType->>PGobject: setValue(value.toString())
        JsonType-->>PreparedStatement: jsonObject
        JsonType->>PreparedStatement: setObject(column, jsonObject)
    end
Loading

File-Level Changes

Change Details Files
Introduce JsonType to map PostgreSQL json/jsonb columns to dbUnit String-based data type with reflection-based PGobject handling and explicit null safety.
  • Implement JsonType extending AbstractDataType, storing a specific sqlTypeName ("json" or "jsonb") and exposing it via getSqlTypeName().
  • Use reflection to construct and configure org.postgresql.util.PGobject instances for non-null values in setSqlValue(), including setting type and value based on sqlTypeName and value.toString().
  • Handle null values safely in setSqlValue() by binding SQL NULL with Types.OTHER, and in typeCast() by returning null for null input.
  • Provide getSqlValue() implementation that reads column contents as String via ResultSet.getString().
src/main/java/org/dbunit/ext/postgresql/JsonType.java
Teach PostgresqlDataTypeFactory to recognize sql type OTHER columns with json/jsonb type names and return JsonType instances.
  • Extend createDataType() conditional chain to detect sqlTypeName "json" or "jsonb" when sqlType is Types.OTHER.
  • Construct a JsonType with the exact sqlTypeName so PGobject binding matches the column type without relying on implicit casts.
src/main/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactory.java
Add unit tests ensuring JsonType behavior (constructor semantics, type casting, and null handling in setSqlValue) and factory mapping for json/jsonb.
  • Create JsonTypeTest extending AbstractPostgresqlStringDataTypeTest to validate basic DataType characteristics for json.
  • Add tests for JsonType constructor storing sqlTypeName and throwing NullPointerException when passed null.
  • Verify typeCast() returns string representations for JSON object/array strings and null for null input.
  • Add Mockito-based test confirming setSqlValue(null, ...) does not throw and calls PreparedStatement.setNull(column, Types.OTHER).
  • Add PostgresqlDataTypeFactoryTest cases asserting that sql type OTHER with typeName "json" or "jsonb" yields JsonType and that getSqlTypeName() matches the type name.
src/test/java/org/dbunit/ext/postgresql/JsonTypeTest.java
src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java
Add integration test that round-trips json and jsonb columns, including null values, through a real PostgreSQL database and verifies jsonb comparison via parsed document structure.
  • Create PostgresqlJsonIT gated by dbunit.profile=postgresql system property, setting DatabaseConfig.PROPERTY_DATATYPE_FACTORY to PostgresqlDataTypeFactory.
  • Set up and tear down a json_test table with json and jsonb columns, including connection handling mirroring existing PostgreSQL ITs.
  • Load FlatXmlDataSet with JSON values and a null row, using ReplacementDataSet to map "[NULL]" placeholders to actual nulls.
  • Assert table metadata reports sql type OTHER and sql type names "json" and "jsonb" for DATA and DATA_B columns.
  • Execute CLEAN_INSERT and then verify round-tripped values: compare json and jsonb via Jackson ObjectMapper.readTree() for structural equality, and assert nulls remain null.
src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java
Document the new JsonType feature and its usage, and record the change in the project change log.
  • Add changes.xml entry for issue 574 describing JsonType, its handling of json/jsonb via PGobject reflection, and explicit null handling semantics.
  • Update PostgreSQL documentation (databases/postgresql.adoc) to mention JsonType support for json/jsonb and cross-link IsActualEqualToExpectedJsonValueComparer for semantic JSON comparisons.
src/changes/changes.xml
src/site/asciidoc/databases/postgresql.adoc

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jeffjensen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 26 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 81a73d90-d56f-4329-838e-86b74275949d

📥 Commits

Reviewing files that changed from the base of the PR and between b024389 and fff0563.

📒 Files selected for processing (5)
  • src/main/java/org/dbunit/ext/postgresql/JsonType.java
  • src/site/asciidoc/databases/postgresql.adoc
  • src/test/java/org/dbunit/ext/postgresql/JsonTypeTest.java
  • src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java
  • src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java
📝 Walkthrough

Walkthrough

Adds PostgreSQL json and jsonb support through a new JsonType, factory integration, unit and integration tests, documentation, and a changelog entry.

Changes

PostgreSQL JSON support

Layer / File(s) Summary
JSON type adapter
src/main/java/org/dbunit/ext/postgresql/JsonType.java
Adds string-based reads and casts, null handling, and reflective PGobject binding for configured json or jsonb types.
Factory integration and validation
src/main/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactory.java, src/test/java/org/dbunit/ext/postgresql/JsonTypeTest.java, src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java, src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java
Maps PostgreSQL json and jsonb types to JsonType. Tests cover type names, casting, null binding, metadata, insertion, and round trips.
Documentation and changelog
src/site/asciidoc/databases/postgresql.adoc, src/changes/changes.xml
Documents type recognition, raw-text handling, literal comparisons, JSON value comparison, and the new support entry.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PostgresqlDataTypeFactory
  participant JsonType
  participant PostgreSQL
  Client->>PostgresqlDataTypeFactory: request datatype for json or jsonb
  PostgresqlDataTypeFactory-->>Client: return configured JsonType
  Client->>JsonType: bind JSON value
  JsonType->>PostgreSQL: bind typed PGobject
  PostgreSQL-->>JsonType: return JSON column value
  JsonType-->>Client: return string value or null
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding PostgreSQL json and jsonb support to PostgresqlDataTypeFactory.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 574-postgresql-json-type

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In JsonType, consider throwing IllegalArgumentException instead of NullPointerException when sqlTypeName is null to more clearly signal invalid caller input rather than a null dereference.
  • The getJson() reflection code could be simplified by catching a broader ReflectiveOperationException (or grouping the current catch blocks) to reduce repetition and make error handling easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In JsonType, consider throwing IllegalArgumentException instead of NullPointerException when sqlTypeName is null to more clearly signal invalid caller input rather than a null dereference.
- The getJson() reflection code could be simplified by catching a broader ReflectiveOperationException (or grouping the current catch blocks) to reduce repetition and make error handling easier to maintain.

## Individual Comments

### Comment 1
<location path="src/main/java/org/dbunit/ext/postgresql/JsonType.java" line_range="134-135" />
<code_context>
+
+        try
+        {
+            final Class aPGObjectClass = super.loadClass(
+                    "org.postgresql.util.PGobject", connection);
+            final Constructor ct = aPGObjectClass.getConstructor();
+            tempJson = ct.newInstance();
</code_context>
<issue_to_address>
**nitpick:** Avoid using raw Class types in the reflection code.

Using the raw Class type here removes generics-based type safety and leads to unchecked operations later. Please change this and the related Constructor/Method declarations to use `Class<?>` (and typed constructor/method references) to keep the reflection code type-safe and idiomatic without altering runtime behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/main/java/org/dbunit/ext/postgresql/JsonType.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
src/test/java/org/dbunit/ext/postgresql/JsonTypeTest.java (1)

117-119: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use AssertJ instead of assertDoesNotThrow.

The rest of the file uses AssertJ. assertThatCode(...).doesNotThrowAnyException() keeps one assertion library and supports the .as() message style.

♻️ Proposed refactor
-        assertDoesNotThrow(
-                () -> type.setSqlValue(null, 1, statement),
-                "setSqlValue() should not throw NullPointerException when value is null.");
+        assertThatCode(() -> type.setSqlValue(null, 1, statement))
+                .as("setSqlValue() should not throw NullPointerException when value is null.")
+                .doesNotThrowAnyException();

Replace the import:

-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.assertj.core.api.Assertions.assertThatCode;

As per coding guidelines: "prefer AssertJ, add .as() failure messages ending with a period".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/ext/postgresql/JsonTypeTest.java` around lines 117 -
119, Replace the JUnit assertDoesNotThrow assertion in JsonTypeTest with
AssertJ’s assertThatCode(...).doesNotThrowAnyException(), preserving the
null-value behavior check and expressing the failure message through .as() with
a trailing period. Remove the now-unused JUnit assertion import.

Source: Coding guidelines

src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java (1)

85-111: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

End the .as() messages with a period.

The messages on lines 85, 103, 105, 109, and 111 have no trailing period. The messages on lines 125 through 135 do. Align them.

As per coding guidelines: "add .as() failure messages ending with a period".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java` around lines
85 - 111, Update the AssertJ `.as()` messages in the affected PostgreSQL JSON
integration test, including the assertions for the connection and DATA/DATA_B
column types and names, so each message ends with a period. Preserve the
assertion logic and align these messages with the already-punctuated messages
later in the test.

Source: Coding guidelines

src/main/java/org/dbunit/ext/postgresql/JsonType.java (3)

73-83: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Validate sqlTypeName before the super() call, or use Objects.requireNonNull.

The super(...) call runs before the null check. AbstractDataType therefore receives a null type name first. The thrown exception is still a NullPointerException, so behavior matches the test. Objects.requireNonNull inside the super() argument makes the intent explicit and fails earlier.

♻️ Proposed refactor
     public JsonType(final String sqlTypeName)
     {
-        super(sqlTypeName, Types.OTHER, String.class, false);
-
-        if (sqlTypeName == null)
-        {
-            throw new NullPointerException(
-                    "The parameter 'sqlTypeName' must not be null");
-        }
-        this.sqlTypeName = sqlTypeName;
+        super(Objects.requireNonNull(sqlTypeName,
+                "The parameter 'sqlTypeName' must not be null"), Types.OTHER,
+                String.class, false);
+
+        this.sqlTypeName = sqlTypeName;
     }

Add the import:

import java.util.Objects;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/dbunit/ext/postgresql/JsonType.java` around lines 73 - 83,
Update the JsonType constructor’s super call to validate sqlTypeName before
passing it to AbstractDataType, using Objects.requireNonNull or an equivalent
inline check. Remove the redundant post-super null check while preserving the
existing exception message.

147-162: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the five catch clauses with one catch (final ReflectiveOperationException e) clause. Remove the unused InvocationTargetException import.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/dbunit/ext/postgresql/JsonType.java` around lines 147 -
162, In JsonType’s reflection handling, replace the five separate catches for
ClassNotFoundException, InvocationTargetException, NoSuchMethodException,
IllegalAccessException, and InstantiationException with one catch (final
ReflectiveOperationException e) that preserves the existing TypeCastException
wrapping. Remove the now-unused InvocationTargetException import.

124-145: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Parameterize reflection types and centralize the repeated PGobject block. Use Class<?> and Constructor<?> in JsonType. The same reflection sequence is duplicated in CitextType, GenericEnumType, InetType, and UuidType; extract it into a focused package-private class.

src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java (1)

99-125: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add .as() failure messages, and consider isInstanceOfSatisfying to drop the cast.

Both new tests cover the json and jsonb branches correctly. The assertions have no .as() description. The rest of the file also omits them, so this is a small consistency improvement rather than a defect.

♻️ Proposed refactor for the `json` test
         final DataType result = instance.createDataType(sqlType, sqlTypeName);
-        assertThat(result).isInstanceOf(JsonType.class);
-        assertThat(((JsonType) result).getSqlTypeName()).isEqualTo("json");
+        assertThat(result).as("createDataType() should return a JsonType for json.")
+                .isInstanceOfSatisfying(JsonType.class,
+                        jsonType -> assertThat(jsonType.getSqlTypeName())
+                                .as("The JsonType should keep the json sql type name.")
+                                .isEqualTo("json"));

As per coding guidelines: "prefer AssertJ, add .as() failure messages ending with a period".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java`
around lines 99 - 125, Add descriptive AssertJ `.as()` messages ending with
periods to the assertions in
`testCreateJsonType_withJsonTypeName_returnsJsonTypeInstance` and
`testCreateJsonType_withJsonbTypeName_returnsJsonTypeInstance`; optionally
replace the instance assertion and cast with `isInstanceOfSatisfying` while
preserving the existing type-name checks.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/site/asciidoc/databases/postgresql.adoc`:
- Around line 12-15: Update the PostgreSQL type-mapping documentation to state
that `oid` maps to `PostgreSQLOidDataType` only when the JDBC type is
`Types.BIGINT` and the SQL type name is `oid`, while leaving the other mappings
and DefaultDataTypeFactory fallback unchanged.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java`:
- Line 1: Add the project-standard DbUnit LGPL license header at the beginning
of PostgresqlJsonIT.java, before the package declaration, matching the header
used by the other new files in the PR.
- Around line 56-60: Update PostgresqlJsonIT.java lines 56-60 by wrapping the
Statement created in the fixture setup in try-with-resources and removing
stat.close(); update lines 70-79 by applying try-with-resources to the teardown
Statement and moving _connection.close() and _connection = null into a finally
block so cleanup occurs even when execution fails.
- Around line 98-113: Update the metadata assertions in PostgresqlJsonIT’s
column loop to track whether DATA and DATA_B were encountered, then assert after
iteration that both columns were checked. Preserve the existing type and SQL
type-name assertions for each column.

---

Nitpick comments:
In `@src/main/java/org/dbunit/ext/postgresql/JsonType.java`:
- Around line 73-83: Update the JsonType constructor’s super call to validate
sqlTypeName before passing it to AbstractDataType, using Objects.requireNonNull
or an equivalent inline check. Remove the redundant post-super null check while
preserving the existing exception message.
- Around line 147-162: In JsonType’s reflection handling, replace the five
separate catches for ClassNotFoundException, InvocationTargetException,
NoSuchMethodException, IllegalAccessException, and InstantiationException with
one catch (final ReflectiveOperationException e) that preserves the existing
TypeCastException wrapping. Remove the now-unused InvocationTargetException
import.

In `@src/test/java/org/dbunit/ext/postgresql/JsonTypeTest.java`:
- Around line 117-119: Replace the JUnit assertDoesNotThrow assertion in
JsonTypeTest with AssertJ’s assertThatCode(...).doesNotThrowAnyException(),
preserving the null-value behavior check and expressing the failure message
through .as() with a trailing period. Remove the now-unused JUnit assertion
import.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java`:
- Around line 99-125: Add descriptive AssertJ `.as()` messages ending with
periods to the assertions in
`testCreateJsonType_withJsonTypeName_returnsJsonTypeInstance` and
`testCreateJsonType_withJsonbTypeName_returnsJsonTypeInstance`; optionally
replace the instance assertion and cast with `isInstanceOfSatisfying` while
preserving the existing type-name checks.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java`:
- Around line 85-111: Update the AssertJ `.as()` messages in the affected
PostgreSQL JSON integration test, including the assertions for the connection
and DATA/DATA_B column types and names, so each message ends with a period.
Preserve the assertion logic and align these messages with the
already-punctuated messages later in the test.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2018b18a-965e-4a24-8ef9-43593e3b7fbf

📥 Commits

Reviewing files that changed from the base of the PR and between 3378ef9 and b024389.

📒 Files selected for processing (7)
  • src/changes/changes.xml
  • src/main/java/org/dbunit/ext/postgresql/JsonType.java
  • src/main/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactory.java
  • src/site/asciidoc/databases/postgresql.adoc
  • src/test/java/org/dbunit/ext/postgresql/JsonTypeTest.java
  • src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java
  • src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java

Comment thread src/site/asciidoc/databases/postgresql.adoc Outdated
Comment thread src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java
Comment thread src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java Outdated
Comment thread src/test/java/org/dbunit/ext/postgresql/PostgresqlJsonIT.java
@jeffjensen

Copy link
Copy Markdown
Member Author

All fixed in 326ef32f unless noted otherwise.

Applied (nitpick-level, no inline thread to reply on):

  • JsonTypeTest: assertDoesNotThrow -> AssertJ assertThatCode(...).as(...).doesNotThrowAnyException(), matching the rest of the file.
  • PostgresqlJsonIT: added trailing periods to the 5 .as() messages that were missing them.
  • JsonType constructor: Objects.requireNonNull(sqlTypeName, ...) inside the super() call instead of a null check after it. Kept the exception type as NullPointerException rather than switching to IllegalArgumentException (Sourcery's suggestion) - GenericEnumType, right next to this class, already does the identical null-guard-on-a-sql-type-name-constructor-arg pattern and throws NullPointerException, and JsonTypeTest already asserts that type; wanted to stay consistent with the established sibling rather than introduce a second convention.
  • JsonType#getJson(): collapsed the 5 catch blocks into one catch (final ReflectiveOperationException e) (both of you flagged this); removed the now-unused InvocationTargetException import.
  • PostgresqlDataTypeFactoryTest: added .as() messages to the 2 new json/jsonb tests.

Declined:

  • Extracting the PGobject-reflection sequence into a shared helper across CitextType/GenericEnumType/InetType/UuidType/JsonType - agreed it's real duplication, but 4 of those 5 files predate this PR and are out of its scope; left as a possible future refactor rather than touching untouched, already-shipped classes here.
  • isInstanceOfSatisfying restructuring in PostgresqlDataTypeFactoryTest - kept the existing isInstanceOf + cast form instead, since that's what the file's other 7 tests already use; .as() messages alone get the consistency win without a shape mismatch against its neighbors.

Individual replies posted on the other inline comments (Class/Constructor typing, the oid/BIGINT doc wording, the metadata-loop assert-nothing gap, try-with-resources) with two declined there too (LGPL header on PostgresqlJsonIT, the OpenGrep SQL-injection flag on a hardcoded test DDL string) - reasoning inline on each.

Full unit suite (2070 tests) and the full postgresql-16 Failsafe IT suite (360 tests) both green after all of the above; mvnw clean install site still builds clean with the doc wording change.

…ctory

PostgresqlDataTypeFactory had no recognition for PostgreSQL's native
json/jsonb columns (reported as sql type OTHER), so they fell through
to DefaultDataTypeFactory with no dedicated read/write handling.

Add JsonType, following the same reflection-based PGobject approach as
UuidType/InetType/CitextType so dbUnit doesn't need a compile-time
dependency on the PostgreSQL driver. One instance handles a single sql
type name ("json" or "jsonb") since PostgreSQL has no implicit cast
between the two; PostgresqlDataTypeFactory constructs the matching
instance per column automatically.

* Unlike the issue reporter's original 2015 patch attachment, which a
  prior maintainer reply already flagged as NPEing from setSqlValue()
  on a null value, this implementation explicitly null-checks in both
  setSqlValue() (binds sql NULL) and typeCast() (returns null).
* Add JsonTypeTest (9 cases, including a Mockito-based regression test
  for the null setSqlValue() path) and 2 new PostgresqlDataTypeFactoryTest
  cases.
* Add PostgresqlJsonIT, round-tripping json and jsonb columns (including
  a null row) through a live PostgreSQL 16 container; jsonb assertions
  compare parsed document structure since PostgreSQL reformats jsonb
  text on storage.
* Document JsonType in databases/postgresql.adoc, cross-linking
  IsActualEqualToExpectedJsonValueComparer for semantic JSON comparison.

Refs: 574

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017rt6YcFdhBCwafLp6n7mcZ
@jeffjensen
jeffjensen force-pushed the 574-postgresql-json-type branch from b024389 to fff0563 Compare August 11, 2026 02:24
@jeffjensen
jeffjensen merged commit 63011ea into main Aug 11, 2026
29 checks passed
@jeffjensen
jeffjensen deleted the 574-postgresql-json-type branch August 11, 2026 02:27
@jeffjensen jeffjensen linked an issue Aug 11, 2026 that may be closed by this pull request

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fff05630f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Override
public Object typeCast(final Object value) throws TypeCastException
{
return value == null ? null : value.toString();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat missing JSON cells as null

When a flat-XML (or other sparse) expected row omits a json/jsonb attribute after the table metadata already includes that column, ITable.getValue() returns ITable.NO_VALUE. Default assertions and SortedTable compare through DataType.compare(), which reaches this typeCast() method; converting the sentinel with toString() makes an omitted expected JSON cell compare as a random object string instead of matching a database NULL, unlike the string-like datatypes this adapter replaces. Please handle ITable.NO_VALUE the same as null here.

Useful? React with 👍 / 👎.

} else if ("citext".equals(sqlTypeName))
{
return new CitextType();
} else if ("json".equals(sqlTypeName) || "jsonb".equals(sqlTypeName))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid ordering raw json columns

For a PostgreSQL table without a primary key when DatabaseConfig.FEATURE_SORT_ALL_COLUMNS_WHEN_NO_PRIMARY_KEY is enabled, DatabaseDataSet.getSelectStatement() orders by every non-LOB column. The json half of this branch now makes those columns known non-LOB columns instead of being ignored as unknown, so reading such a table generates ORDER BY on a json column, which PostgreSQL rejects because json has no ordering operator. Please exclude json columns from that fallback ordering or otherwise avoid adding them to the generated ORDER BY.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgresqlDataTypeFactory support json type

1 participant