Files
hibernate-demo/json-columns/README.md
T

66 lines
4.9 KiB
Markdown

# json-columns
Companion module for the ankurm.com article **JSON Columns in Hibernate 7: `@JdbcTypeCode(SqlTypes.JSON)` and Querying JSONB on PostgreSQL**
(https://ankurm.com/hibernate-json-column-jdbctypecode-jsonb-postgresql/).
Every claim in the article comes from a test or script here; each writes what it observed to `output/`.
The tests run against a real PostgreSQL 18 and a real MySQL 8.0 server started without Docker (see Quickstart).
## Versions
| Component | Version | Notes |
|---|---|---|
| Hibernate ORM | `7.4.14.Final` | newest 7.x GA on Maven Central on 2026-10-30; overrides the `7.4.13.Final` Spring Boot 4.1.2 manages |
| Spring Boot | `4.1.2` | parent POM; Spring Data JPA `4.1.2` |
| Jackson | `3.1.7` (`tools.jackson`) | what Boot 4.1.2 manages; Jackson 2 `2.22.4` only in the `jackson2` profile |
| PostgreSQL / driver | `18.6` / `42.7.14` | `embedded-postgres-binaries-linux-amd64` 18.6.0 from Maven Central, no Docker |
| MySQL / driver | `8.0.46` / Connector/J `9.7.0` | Ubuntu 24.04 `mysql-server-core-8.0` package |
| hypersistence-utils | `hypersistence-utils-hibernate-73` `3.16.0` | `hypersistence` profile only (A10) |
| Java | `25` (Temurin 25.0.5+8) | |
## Quickstart
```bash
./scripts/start-databases.sh # PostgreSQL on 55432 and MySQL on 53306 (needs root: both servers refuse to run as root, so it makes two OS users)
./scripts/run-all.sh # versions + mvn clean test + hypersistence runs + FormatMapper matrix; regenerates everything in output/
```
Point the tests at other servers with `PG_URL`, `PG_USER`, `MYSQL_URL`, `MYSQL_USER` (defaults in `src/test/java/com/ankurm/jsoncolumns/Db.java`).
Timings in `output/07-indexing-explain.txt` drift between runs; plan shapes and row counts are asserted.
## Layout
| Path | What |
|---|---|
| `src/main/java/.../model` | `Product` (Map, List, record, POJO columns), `Dimensions` (record), `Specs` (POJO with `equals()`), `Event` (indexing table), `ProductRepository`, `SharedMapperConfig`, `JsonColumnsApplication` |
| `src/test/java/.../A01..A11` | one test class per output file (A10 lives in `src/hypersistence-test`, active with `-Phypersistence`) |
| `src/test/java/.../Db.java`, `SqlLog.java`, `Transcript.java`, `HqlRunner.java`, `Seed.java` | plain-Hibernate bootstrap, SQL capture, transcript writer, shared HQL case runner, shared sample rows |
| `src/test/java/.../FormatMapperProbe.java` | `main()` run by `scripts/format-mapper-matrix.sh` under nine classpaths |
| `scripts/` | `start-databases.sh`, `run-all.sh`, `versions.sh`, `format-mapper-matrix.sh`, `javap.sh`, `maven-facts.sh` |
## Output
| File | What it shows |
|---|---|
| `00-versions.txt` | JDK, resolved library versions, PostgreSQL and MySQL server versions |
| `01-ddl-postgresql.txt` | the `CREATE TABLE` Hibernate emits for six JSON mappings (json vs jsonb), `json` vs `jsonb` storage differences |
| `02-mapping-roundtrip.txt` | Map / List / record / POJO round trip: INSERT, stored JSON, Java types that come back, null vs empty |
| `03-dirty-checking.txt` | in-place mutations detected or not, spurious UPDATEs (no `equals()`, `BigDecimal`), `@DynamicUpdate` |
| `04-hql-json-functions-postgresql.txt` | every Hibernate 7.4 HQL JSON function run on PostgreSQL 18: generated SQL and result |
| `05-embeddable-json-postgresql.txt` | `@Embeddable` stored as JSON, navigated in HQL without `json_value()` |
| `06-native-jsonb-operators.txt` | `->>`, `@>`, `?`, `@?`, `@@` in native queries and what Hibernate's parameter parser does to them |
| `07-indexing-explain.txt` | 50,000 rows, `EXPLAIN (ANALYZE)` before and after GIN, `jsonb_path_ops` and expression indexes |
| `08-mysql.txt` | DDL, round trip, dirty checking, HQL functions, native functions and indexes on MySQL 8.0 |
| `09-format-mapper-matrix.txt` | which `FormatMapper` Hibernate picks under nine classpath / setting combinations |
| `09-format-mapper-inprocess.txt` | schema evolution failures, `@JsonIgnoreProperties`, a custom `JsonMapper`, `java.time` inside a Map |
| `10-hypersistence-*.txt` | `@TypeDef` is gone; hypersistence-utils `JsonType` on Hibernate 7.4.14 with and without Jackson 2 |
| `11-spring-boot.txt` | Spring Data repositories with native and HQL JSON queries; Boot's `JsonMapper` is not Hibernate's |
| `12-javap-deepcopy.txt` | `javap` of the JSON snapshot copy (`deepCopy` = serialise then parse) and of `areEqual` (`Objects.equals`) |
| `13-maven-facts.txt` | release dates and `maven-metadata.xml` facts read from Maven Central (versions callout, hypersistence-utils vs the old hibernate-types) |
## Not covered (not run)
Oracle, SQL Server, DB2, H2 and MariaDB JSON dialects, Hibernate's JSON mapping with `SqlTypes.JSON_ARRAY`, `@Embeddable` aggregates on MySQL beyond a single query,
`jsonb_path_ops` plus `@?` path indexing, PostgreSQL `jsonb_ops` write amplification, concurrent-write load, `JsonB` (Yasson) as the format mapper, and Hibernate 8.
MIT — see [LICENSE](../LICENSE).