---
name: hibernate6-uuid-entity-mapping
source: https://app.decimal.ai/s/hibernate6-uuid-entity-mapping@1/SKILL.md
source_sha256: e556a4758c8a
---

# Hibernate 6 UUID entity mapping

## Contract

Enforces the **current** way to map a UUID-identified JPA/Hibernate entity, as defined by Hibernate ORM 6
and Jakarta Persistence 3.1. Apply whenever you generate an `@Entity` whose identifier is a
`java.util.UUID` (especially a random / RFC 4122 version-4 id) or that stores a collection of scalar
values with `@ElementCollection`. The base model reaches for the Hibernate 5 recipe by default; this
skill pins the Hibernate 6 / Jakarta tokens instead.

## Rules

1. **Namespace is `jakarta.persistence`, never `javax.persistence`.** Since Jakarta EE 9 / JPA 3.0 every
   persistence annotation moved packages: `jakarta.persistence.Entity`, `jakarta.persistence.Id`,
   `jakarta.persistence.GeneratedValue`, `jakarta.persistence.Column`, `jakarta.persistence.Table`,
   `jakarta.persistence.ElementCollection`, `jakarta.persistence.CollectionTable`,
   `jakarta.persistence.JoinColumn`. Hibernate 6 requires this namespace.

2. **The id field is typed `java.util.UUID`.** Never a `Long`/`Integer` auto-increment, never a `String`.
   Do not fall back to `@GeneratedValue(strategy = GenerationType.IDENTITY)`.

3. **Generate the id with Hibernate's `@UuidGenerator`, not the legacy `@GenericGenerator`.** The id
   carries `@Id`, `@GeneratedValue`, and `@UuidGenerator` (from `org.hibernate.annotations`). Do NOT use
   the removed Hibernate 5 string-strategy form:
   `@GeneratedValue(generator = "uuid4")` + `@GenericGenerator(name = "uuid4", strategy = "org.hibernate.id.UUIDGenerator")`.

4. **Version 4 (random) == `@UuidGenerator(style = UuidGenerator.Style.RANDOM)`.** `Style.RANDOM` maps to
   `UUID.randomUUID()` — an RFC 4122 version-4 value. `Style.TIME` is time-based (not version 4); `Style.AUTO`
   is the default and behaves as `RANDOM`. When the requirement says "version 4" or "random", write
   `style = UuidGenerator.Style.RANDOM` explicitly.

5. **No String-based `@Type`.** Hibernate 6.0 removed `@Type(type = "...")`; the `type` string attribute
   no longer exists. A `java.util.UUID` maps natively with NO `@Type` at all. Never write
   `@Type(type = "org.hibernate.type.UUIDCharType")`, `uuid-char`, `pg-uuid`, or `uuid2`. Drop
   `columnDefinition = "uuid"` unless you deliberately want a vendor-specific DDL type.

6. **`@ElementCollection` is configured with `@CollectionTable` + `@JoinColumn` + `@Column`.** A collection
   of scalars (e.g. `List<UUID>` or `List<String>`) uses `@ElementCollection`, then `@CollectionTable(name =
   "...", joinColumns = @JoinColumn(name = "..."))` to name the side table and its foreign key, then
   `@Column(name = "...")` for the value column. Collection *elements* are supplied by the application and
   mapped natively — do not attach `@UuidGenerator`, `@GenericGenerator`, or a String `@Type` to them.

## Worked examples

**Primary key — legacy default → current form.**
```java
// BEFORE (Hibernate 5 idiom the base emits by default):
import javax.persistence.*;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;

@Id
@GeneratedValue(generator = "uuid4")
@GenericGenerator(name = "uuid4", strategy = "org.hibernate.id.UUIDGenerator")
@Type(type = "org.hibernate.type.UUIDCharType")
@Column(name = "id", columnDefinition = "uuid", updatable = false, nullable = false)
private UUID id;

// AFTER (Hibernate 6 + Jakarta):
import jakarta.persistence.*;
import org.hibernate.annotations.UuidGenerator;
import java.util.UUID;

@Id
@GeneratedValue
@UuidGenerator(style = UuidGenerator.Style.RANDOM)
@Column(name = "id", updatable = false, nullable = false)
private UUID id;
```
`javax` → `jakarta`; the `@GenericGenerator` string strategy and the String `@Type` are gone; the random
(version-4) style is declared with `@UuidGenerator(style = UuidGenerator.Style.RANDOM)`.

**Element collection of UUIDs — legacy default → current form.**
```java
// BEFORE:
@ElementCollection
@CollectionTable(name = "dog_attribute", joinColumns = @JoinColumn(name = "dog_id"))
@Column(name = "attribute", columnDefinition = "uuid")
@Type(type = "org.hibernate.type.UUIDCharType")
private List<UUID> attributes;

// AFTER:
@ElementCollection
@CollectionTable(name = "dog_attribute", joinColumns = @JoinColumn(name = "dog_id"))
@Column(name = "attribute")
private List<UUID> attributes;
```
The side table + foreign-key column stay; the removed String `@Type` and the unneeded `columnDefinition`
drop away — `List<UUID>` maps natively in Hibernate 6.

## Edge cases & exceptions

- **"UUID id" with no version stated.** Default to `@UuidGenerator(style = UuidGenerator.Style.RANDOM)`
  (RFC 4122 version 4) — it is the modern default and matches `UUID.randomUUID()`.
- **JPA-portable variant.** `@GeneratedValue(strategy = GenerationType.UUID)` (Jakarta Persistence 3.1) is
  also valid, but the JPA spec does not guarantee a specific UUID version. When the task explicitly wants
  version 4, prefer Hibernate's `@UuidGenerator(style = Style.RANDOM)`, which does.
- **Assigning ids in application code.** If the id is set by the caller (no generation), keep `@Id` and the
  `UUID` type and simply omit `@GeneratedValue`/`@UuidGenerator`.
- **PostgreSQL native `uuid` column.** You may add `@JdbcTypeCode(SqlTypes.UUID)` if you need to force the
  native SQL type; this replaces the old `columnDefinition = "uuid"` / `pg-uuid` hacks. Still no String `@Type`.
- **`Set` instead of `List`.** `Set<UUID>` / `Set<String>` collections use the exact same
  `@ElementCollection` + `@CollectionTable` + `@JoinColumn` + `@Column` annotations.

## Do / Don't

- DON'T import `javax.persistence.*`. ALWAYS import `jakarta.persistence.*`.
- DON'T use `@GeneratedValue(generator = "uuid4")` + `@GenericGenerator(strategy = "org.hibernate.id.UUIDGenerator")`.
  ALWAYS use `@UuidGenerator`.
- DON'T write `@Type(type = "org.hibernate.type.UUIDCharType")` (or any `@Type(type = "...")`). ALWAYS let
  `java.util.UUID` map natively.
- DON'T type the id as `Long`, `Integer`, or `String`. ALWAYS type it `java.util.UUID`.
- DON'T leave the version implicit when the task says "version 4"/"random". ALWAYS write
  `style = UuidGenerator.Style.RANDOM`.
- DON'T drop `@CollectionTable`/`@JoinColumn` from an `@ElementCollection`. ALWAYS name the side table and
  its foreign key.

## Common mistakes (the base model's wrong defaults)

- Emitting the whole Hibernate 5 recipe: `javax.persistence`, `@GenericGenerator`, and `@Type(type = "...")`.
- Using `@GeneratedValue(strategy = GenerationType.AUTO)` and hoping for a UUID instead of declaring
  `@UuidGenerator`.
- Keeping `columnDefinition = "uuid"` plus a String `@Type`, which no longer compiles under Hibernate 6.
- Forgetting `style = UuidGenerator.Style.RANDOM` when version 4 is explicitly required.
- Annotating collection elements with a generator or `@Type` as if they were generated identifiers.

## Quick checklist

- [ ] Imports are `jakarta.persistence.*` (not `javax.persistence.*`).
- [ ] Id field is `java.util.UUID`.
- [ ] Id uses `@Id` + `@GeneratedValue` + `@UuidGenerator` (no `@GenericGenerator` string strategy).
- [ ] `@UuidGenerator(style = UuidGenerator.Style.RANDOM)` when version 4 / random is wanted.
- [ ] No `@Type(type = "...")` anywhere; UUID maps natively.
- [ ] `@ElementCollection` has `@CollectionTable(joinColumns = @JoinColumn(...))` + `@Column`.
