jmix icon indicating copy to clipboard operation
jmix copied to clipboard

Deep custom bean validation can break saving of entity via REST

Open knstvk opened this issue 5 months ago • 2 comments

Environment

Jmix version: 2.6.1

Bug Description

There are 2 entities:

@JmixEntity
@Table(name = "REST_ROOT_ENTITY")
@Entity(name = "rest_RootEntity")
@ValidRootEntity
public class RootEntity {
    @JmixGeneratedValue
    @Column(name = "ID", nullable = false)
    @Id
    private UUID id;

    @NotNull
    @InstanceName
    @Column(name = "NAME")
    private String name;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "NESTED_ENTITY_ID")
    private NestedEntity nestedEntity;

@JmixEntity
@Table(name = "REST_NESTED_ENTITY")
@Entity(name = "rest_NestedEntity")
public class NestedEntity {
    @JmixGeneratedValue
    @Column(name = "ID", nullable = false)
    @Id
    private UUID id;

    @NotNull
    @InstanceName
    @Column(name = "NAME")
    private String name;

    @NotNull
    @Column(name = "CODE")
    private String code;

The root entity validation includes the nested state:

public class ValidRootEntityValidator implements ConstraintValidator<ValidRootEntity, RootEntity> {

    @Override
    public boolean isValid(RootEntity entity, ConstraintValidatorContext constraintValidatorContext) {
        return entity.getNestedEntity().getCode().equals("test");
    }
}

Trying to save the root entity using JSON which includes the link to nested entity:

{
  "id": "$ROOT_ID$",
  "name": "Entity 1",
  "nestedEntity": {
    "id": "$NESTED_ID$"
  }
}

Got exception:

jakarta.validation.ValidationException: HV000028: Unexpected exception during isValid call.
	at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateSingleConstraint(ConstraintTree.java:186) ~[hibernate-validator-8.0.2.Final.jar:8.0.2.Final]
	at ...
Caused by: java.lang.IllegalStateException: Cannot get unfetched attribute [code] from detached object io.jmix.samples.rest.entity.NestedEntity-cc2d10a7-8f7f-49be-be11-a7ef008c1376 [detached].
	at org.eclipse.persistence.internal.queries.EntityFetchGroup.onUnfetchedAttribute(EntityFetchGroup.java:100) ~[org.eclipse.persistence.core-4.0.6-2-jmix.jar:na]
	at io.jmix.eclipselink.impl.JmixEntityFetchGroup.onUnfetchedAttribute(JmixEntityFetchGroup.java:78) ~[jmix-eclipselink-2.7.999-SNAPSHOT.jar:na]
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.processUnfetchedAttribute(EntityManagerImpl.java:2996) ~[org.eclipse.persistence.jpa-4.0.6-2-jmix.jar:na]
	at io.jmix.samples.rest.entity.NestedEntity._persistence_checkFetched(NestedEntity.java) ~[main/:na]
	at io.jmix.samples.rest.entity.NestedEntity._persistence_get_code(NestedEntity.java) ~[main/:na]
	at io.jmix.samples.rest.entity.NestedEntity.getCode(NestedEntity.java:49) ~[main/:na]
	at io.jmix.samples.rest.entity.ValidRootEntityValidator.isValid(ValidRootEntityValidator.java:26) ~[main/:na]
	at io.jmix.samples.rest.entity.ValidRootEntityValidator.isValid(ValidRootEntityValidator.java:22) ~[main/:na]

Steps To Reproduce

See tests in the linked PR.

knstvk avatar Aug 26 '25 13:08 knstvk

Possible solution: Complete fetch plans with fields involved in validation.

dtaimanov avatar Oct 28 '25 12:10 dtaimanov

Check also https://github.com/jmix-framework/jmix/issues/3344

dtaimanov avatar Nov 10 '25 12:11 dtaimanov