@NotEmpty annotation doesn't work on a collection

Hi,

I’m trying to validate an entity before saving, I need to check if a collection is not empty. I use @NotEmpty annotation on the field, but I still can save the object with an empty collection. However, @NotNull annotation on simple fields works perfectly. What could be the reason?

//...
public class Sale extends AbstractDocument {

    @NotNull //works well
    @JoinColumn(name = "COMPANY_ID")
    @OneToOne(fetch = FetchType.LAZY)
    private Company company;
//...
    @NotEmpty // Ignored - why?
    @OnDelete(DeletePolicy.CASCADE)
    @Composition
    @OneToMany(mappedBy = "sale")
    private Set<SaleProduct> saleProducts;
//...
}

I’ve also tried to use a custom validator, as described here https://docs.jmix.io/jmix/ui/screens/validation.html
but the method isValid() of my validator is never reached, too

Hi @vadim.vainshtein
Thank you for reporting the problem.
Created issue. We’ll find out what we can do.

As for the “custom validator”, could you explain what you have tried?

Hi Konstantin,
Thank you for your reply. Here is what I’ve tried:

I have an annotation to mark the required field:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(validatedBy = NotEmptySetValidator.class)
public @interface NotEmptySet {
    String message() default "empty set";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

and a validator class:

public class NotEmptySetValidator implements ConstraintValidator<NotEmptySet, Collection<?>> {

    @Override
    public boolean isValid(Collection<?> value, ConstraintValidatorContext context) {
        return !(value == null || value.isEmpty()); // never reached
    }
}

and I mark the field in my class

    @NotEmptySet
    @OnDelete(DeletePolicy.CASCADE)
    @Composition
    @OneToMany(mappedBy = "sale")
    private Set<SaleProduct> saleProducts;

I believe the documentation says about automatic cross-field validation in edit screens if the entity class has a custom annotation with UiCrossFieldChecks group. It’s quite different from what you did.

Yes, that’s what I realized after more careful reading. So still searching for a convenient way to do collection validation. At the moment I have my annotation on collections, and I’m checking them in overrided validateScreen(). But a problem comes when a component is disabled. By default Jmix doesn’t validate disabled components, and I would like to have this behavior on my validation, too. But I haven’t found any good solution for it yet.

What if you just subscribe to the edit screen’s ValidationEvent?

@Subscribe
public void onValidation(ValidationEvent event) {
    if (stepsDc.getItems().isEmpty()) {
        ValidationErrors errors = new ValidationErrors();
        errors.add("Collection is empty");
        event.addErrors(errors);
    }
}
1 Like

Oh, thank you, that is perhaps the best choice for now, I’ll use it! However, I have several similar screens that all inherit from one abstract screen, and I would like to have a really simple one-line method of marking a collection as required. The only thing I can invent is to have a reference to the collection in the superclass and to set it in every inheritor if needed… Not the prittiest idea, but better than nothing.

Agree, we’ll try to make it in the issue I mentioned above.

1 Like