원클릭으로
jmix-create-entity
Create or change a persistent Jmix JPA entity and its required surrounding artifacts.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Create or change a persistent Jmix JPA entity and its required surrounding artifacts.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Open a Jmix entity detail view from a button/action and refresh related data after save.
Add Jmix entity lifecycle event listeners to perform additional actions with saved or loaded entities.
Add complete Jmix message keys for entities, enums, views, actions, and validation text.
Configure or audit Jmix fetch plans in XML views, fragments, DataManager loads, repositories, and entity events when loading references, avoiding N+1 queries, fixing unfetched attribute errors, or tuning data loading.
Add inline editable parent-child composition UI to a Jmix detail view, when a parent entity owns child records edited via a property-bound collection container (no query loader).
Create a Jmix Flow UI detail view with XML descriptor, save-close action, messages, and policies.
| name | jmix-create-entity |
| description | Create or change a persistent Jmix JPA entity and its required surrounding artifacts. |
Use this skill when adding or changing a database-backed Jmix entity.
src/main/java/<base-package>/entity.@JmixEntity, @Entity, @Table.@Id and @JmixGeneratedValue.@Version.@InstanceName on a stable human-readable field or method.nullable, length, precision, and scale constraints from requirements.FetchType.LAZY for relationships.jmix-create-liquibase-changelog.jmix-add-i18n-keys.import io.jmix.core.entity.annotation.JmixGeneratedValue;
import io.jmix.core.metamodel.annotation.InstanceName;
import io.jmix.core.metamodel.annotation.JmixEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Version;
import java.util.UUID;
@JmixEntity
@Table(name = "CUSTOMER")
@Entity
public class Customer {
@JmixGeneratedValue
@Column(name = "ID", nullable = false)
@Id
private UUID id;
@Version
@Column(name = "VERSION", nullable = false)
private Integer version;
@InstanceName
@Column(name = "NAME", nullable = false, length = 100)
private String name;
// getters and setters
}
When a required field "defaults to X" or is "auto-set on create/update"
(e.g. "default now()", "auto-set", "defaults to 0"), the default MUST
apply at the entity layer so a bare DataManager.create() +
DataManager.save() succeeds with the caller never touching the field.
This is the contract: programmatic paths (services, REST, tests) bypass
the UI, so a default that lives only in the view is no default at all.
Three patterns, in order of preference:
Constant default — field initializer
@Column(name = "QUANTITY", nullable = false)
@NotNull
private Integer quantity = 0;
Initial default at creation — @PostConstruct
@PostConstruct fires when Jmix instantiates the entity
(DataManager.create(), Metadata.create(), DataContext.create()),
before the caller sets any field. Works for both JPA entities and DTOs.
@Column(name = "CREATED_AT", nullable = false)
@NotNull
private LocalDateTime createdAt;
@PostConstruct
public void postConstruct() {
createdAt = LocalDateTime.now();
}
Imports (Spring Boot 3 uses jakarta.*, never javax.*): @PostConstruct from jakarta.annotation; @NotNull / @Email from jakarta.validation.constraints.
Auto-set on every save — EntitySavingEvent listener (for
lastUpdated-style fields that must touch on UPDATE too, or for any
cross-entity defaulting):
import io.jmix.core.event.EntitySavingEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class CustomerSavingListener {
@EventListener
public void onSaving(EntitySavingEvent<Customer> event) {
event.getEntity().setLastUpdated(LocalDateTime.now());
}
}
EntitySavingEvent fires before EVERY save (both insert and update),
so the listener covers initial and subsequent timestamps in one place.
Customer must declare the lastUpdated field; for the full event-listener
pattern see jmix-add-entity-event-listener.
| Wrong placement | Why it fails |
|---|---|
Default set only in the detail view's InitEntityEvent | Non-UI saves bypass the view; DataManager.save() hits the @NotNull violation. |
| Default set only in a service mutator that runs on UPDATE | The initial INSERT has no default; @NotNull fails. And a test calling DataManager directly never enters the service. |
Default set in an EntityChangedEvent listener | The listener fires AFTER persist — too late for @NotNull. It reacts to saves; it does not default them. |
| Default set only in the calling UI controller | Programmatic paths (services, REST, tests) bypass it. |
For parent-child aggregates:
@Composition.@OnDelete(DeletePolicy.CASCADE) when child lifecycle belongs to parent.@ManyToOne uses fetch = FetchType.LAZY and optional = false.nullable = false.<collection property=...> (no loader/query), and the parent fetchPlan includes the child property.import io.jmix.core.DeletePolicy;
import io.jmix.core.entity.annotation.OnDelete;
import io.jmix.core.metamodel.annotation.Composition;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
@Composition
@OnDelete(DeletePolicy.CASCADE)
@OneToMany(mappedBy = "parent")
private List<ChildLine> lines; // leave uninitialized — Jmix returns a NotInstantiatedList
@JoinColumn(name = "PARENT_ID", nullable = false)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private Parent parent;
Add audit fields with the Spring Data annotations from org.springframework.data.annotation: @CreatedBy, @CreatedDate, @LastModifiedBy, @LastModifiedDate. For soft delete add @DeletedBy and @DeletedDate from io.jmix.core.annotation — soft-deleted rows are then auto-filtered out of DataManager/JPQL queries.
Non-persistent derived attributes use @JmixProperty + @Transient + @DependsOnProperties({"a", "b"}) (@JmixProperty from io.jmix.core.metamodel.annotation). The same applies to an @InstanceName method: it must carry @DependsOnProperties listing every attribute it reads so they are fetched.
@Embeddable value objects (still annotated @JmixEntity) are supported, as are JPA inheritance strategies (@Inheritance with JOINED, SINGLE_TABLE, or TABLE_PER_CLASS).@Store(name = "...") (defined in application.properties); add-on entities use an entity-name prefix, e.g. @Entity(name = "app_Customer").compileJava does not build the schema — Liquibase does — so Java/DDL
drift is silent. Check Java annotations and the Liquibase changelog side
by side:
nullable / @NotNulllengthprecision and scaleApply common Java validation and persistence mappings when the field semantics are clear:
email should usually have @Email unless the requirements explicitly say otherwise.@Lob plus a matching Liquibase type, not an invented arbitrary length.BigDecimal columns must use the exact required precision and scale in both Java and Liquibase.@JmixEntity.@Data, @Getter, @Setter, etc.) on Jmix entities — they interfere with the entity enhancer and break JPA/Jmix metadata.FetchType.EAGER.NotInstantiatedList/NotInstantiatedSet. Leave collection fields uninitialized; do not assign new ArrayList/new HashSet..java — it passes compile and the clean test boot, but breaks the registry. Confirm every file you wrote is non-empty.