JPA Processing
JPA Processing
Jinx parses JPA metadata during annotation processing and builds a schema model before writing migration data.
Main flow
JpaSqlGeneratorProcessor is the entry point.
It initializes a shared ProcessingContext and these handlers:
EntityHandlerRelationshipHandlerInheritanceHandlerSequenceHandlerEmbeddedHandlerConstraintHandlerElementCollectionHandlerTableGeneratorHandler
For each processing round, Jinx:
- Resets round-level caches in
ProcessingContext - Registers
@Converter(autoApply = true)converters - Registers
@MappedSuperclassand@Embeddable - Processes each
@Entity - Resolves inheritance
- Validates primary keys
- Retries deferred work such as
JOINEDinheritance, missing relationship targets,@ElementCollection, and@MapsId - Writes the final schema JSON
Shared context
ProcessingContext stores the schema model and the state shared by all handlers.
Important parts:
descriptorCache: cachesAttributeDescriptorlists per typemappedSuperclassElementsandembeddableElements: round-local type registriesdeferredEntitiesanddeferredNames: retry queue for unresolved workpkAttributeToColumnMap: used for@MapsId("...")mappedByVisitedSet: prevents recursivemappedByloops
Attribute discovery
Jinx does not read fields and getters separately for every handler. It first builds AttributeDescriptors with AttributeDescriptorFactory.
The factory:
- determines the default access type with
AccessUtils.determineAccessType() - walks the class hierarchy
- includes attributes from
@MappedSuperclass - stops climbing when it reaches an
@Entitysuperclass, so child tables do not duplicate parent table columns - prefers explicit
@Access - otherwise chooses the side that has JPA mapping annotations
- falls back to the entity default access type
This keeps field access, property access, and record components consistent.
Entity processing
EntityHandler processes one entity in this order:
- Create and pre-register
EntityModel - Read table metadata
- Process sequence and table generators
- Process entity-level constraints
- Register secondary tables
- Process composite keys such as
@EmbeddedId - Process attributes through
AttributeDescriptorFactory - Process secondary-table joins
- Process
JOINEDinheritance joins - Queue deferred
@MapsIdwork if needed
Pre-registration matters because related entities may reference each other before both are fully processed.
Why deferred processing exists
Some metadata cannot be finalized on the first pass.
Examples:
- a
JOINEDchild may need a parent primary key that is not ready yet - a relationship may point to an entity processed later
@ElementCollectionmay depend on the owner primary key@MapsIdneeds both primary-key and foreign-key metadata
Jinx re-runs these cases from the deferred queue until dependencies are resolved or no progress is possible.