What is the use case of javax.validation.Payload in Bean Validation API?
Asked Answered
K

2

12

Bean Validation specification defines:

Constraint annotations must define a payload element that specifies the payload with which the constraint declaration is associated. The type of the payload parameter is Payload[].

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

The default value must be an empty array.
Each attachable payload extends Payload.

/**
 * Payload type that can be attached to a given
 * constraint declaration.
 * <p/>
 * Payloads are typically used to carry on metadata information
 * consumed by a validation client.
 * </p>
 * Use of payloads is not considered portable.
 */

I have read its examples, but I don't understand for example, how I can use this metadata in JSF? Can you explain other use cases of payloads in real world? What is the meta data that is carried by payload?

Kent answered 24/11, 2019 at 13:51 Comment(1)
Does this answer your question? What is the use of groups and payload in custom Annotation In Java?Persistent
H
4

Why Use the payload Parameter?

The payload parameter is used to include information about the constraint to code handling validation errors. It allows users to augment a constraint with additional information that isn't covered in the main constraint parameters. The spec uses the example of associating a severity with a validation constraint:

package com.acme.severity;

public class Severity {
    public static class Info implements Payload {};
    public static class Error implements Payload {};
}

public class Address {
    @NotNull(message="would be nice if we had one", payload=Severity.Info.class)
    public String getZipCode() { [...] }

    @NotNull(message="the city is mandatory", payload=Severity.Error.class)
    String getCity() { [...] }
}

The @NotNull annotation doesn't need to know (and can't know) about the application specific Severity class, but the payload parameter ensures that such metadata can be associated with an annotation if needed.

In this case, you could use the severity information to differentiate between violations that only generate warnings vs actual errors that prevent a client from doing something.

How to Access the Metadata?

The payload can be accessed by retrieving the ConstraintDescriptor from the ConstraintViolation that is provided when the specific constraint isn't valid:

private boolean isHardError(ConstraintViolation<Address> violation) {
    var descriptor = violation.getConstraintDescriptor();
    Set<Class<? extends Payload>> = descriptor.getPayload();
    if(payload.contains(Severity.Info.class)) {
        // treat the violation as a warning
        return false;
    } else {
        // treat the violation as an error
        return true;
    }
}
Helenahelene answered 28/7, 2023 at 16:55 Comment(0)
E
-3

Maybe this link will help u.


import javax.validation.*;
import javax.validation.constraints.NotNull;
import java.util.Set;

public class ConstraintPayloadExample2 {
    private static final Validator validator;

    static {
        Configuration<?> config = Validation.byDefaultProvider().configure();
        ValidatorFactory factory = config.buildValidatorFactory();
        validator = factory.getValidator();
        factory.close();
    }

    public interface AppErrorHandler<T> extends Payload {
        void onError (ConstraintViolation<T> violation);
    }

    public static class ErrorEmailSender<T> implements AppErrorHandler<T> {
        @Override
        public void onError (ConstraintViolation<T> violation) {
            System.out.println("Sending email to support team: " +
                                violation.getPropertyPath() + " " +
                                violation.getMessage());
        }
    }

    public static class TestBean {

        @NotNull(payload = {ErrorEmailSender.class})
        private String str;

        public String getStr () {
            return str;
        }

        public void setStr (String str) {
            this.str = str;
        }
    }

    public static void main (String[] args) {
        TestBean bean = new TestBean();

        Set<ConstraintViolation<TestBean>> constraintViolations =
                            validator.validate(bean);

        if (constraintViolations.size() > 0) {
            constraintViolations.stream().forEach(
                                ConstraintPayloadExample2::processError);
        } else {
            //proceed using user object
            System.out.println(bean);
        }
    }


    private static void processError (ConstraintViolation<TestBean> violation) {
        Set<Class<? extends Payload>> payload =
                            violation.getConstraintDescriptor().getPayload();

        payload.forEach(p -> {
            if (AppErrorHandler.class.isAssignableFrom(p)) {
                try {
                    AppErrorHandler errorHandler = (AppErrorHandler) p.newInstance();
                    errorHandler.onError(violation);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
Exaction answered 3/4, 2020 at 12:20 Comment(1)
To me, this answer doesn't look complete. Please, consider using explanations in your answer, not just posting code and a link. I still don't understand what's the purpose of the Payload class here.Arborescent

© 2022 - 2024 — McMap. All rights reserved.