Begin forwarded message:

From: Emmanuel Bernard <emmanuel.bernard@JBOSS.COM>
Date:  June 15, 2009 17:57:48  EDT
To: JSR-303-EG@JCP.ORG
Subject: Re: constraint level payload
Reply-To: Java Community Process JSR #303 Expert List <JSR-303-EG@JCP.ORG>

Done
http://people.redhat.com/~ebernard/validation/#constraintsdefinitionimplementation-constraintdefinition-payload

Pleaase have a look and let me know what you think. I'm not a big fan of forcing this noew attribute on everybody's constraint but I don't see muc more possibilities.

2.1.1.3. payload

Every constraint annotation must define a payload element that specifies which payload the constraint declaration is associated with.

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

The default value must be an empty array.

Each attachable payload extends ConstraintPayload.

/**
 * Payload type that can be attached to a given
 * constraint declaration.
 * Payloads are typically used to carry on metadata information
 * consumed by a validation client.
 *
 * Use of payloads is not considered portable.
 *
 * @author Emmanuel Bernard
 * @author Gerhard Petracek
 */
public interface ConstraintPayload {
}

Payloads are typically used by validation clients to associate some metadata information to a given constraint declaration. Payloads are typically non portable. Describing payloads as interface extensions as opposed to a string based approach allows an easier and more type-safe approach.

One use case for payload shown in Example 2.1, “Use of payload to associate severity to a constraint” is to associate a severity to a constraint. This severity can be exploited by a presentation framework to adjust how a constraint failure is displayed.

Example 2.1. Use of payload to associate severity to a constraint

package com.acme.severity;
public class Severity {
    public static class Info extends ConstraintPayload {};
    public static class Error extends ConstraintPayload {};
}

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 payload information can be retrieved from error reports via ConstraintViolation objects (see Section 4.2, “ConstraintViolation”) or using the metadata API viaConstraintDescriptor objects (see Section 5.5, “ConstraintDescriptor”).


On  May 29, 2009, at 04:49, Emmanuel Bernard wrote:

We have had a few discussions around having a payload on constraints that could be consumed by client frameworks.

There are 4 competing solutions:

#1 Nothing
The argument would be that it's not needed and hence we don't need any payload.
On that subject what are the use cases for such a payload. Please be as specific as possible.

 - We have identified Error / Warn modes which I argued can be solved by groups. I also argued that groups and modes are *not* orthogonal to groups and hence would not lead to a group explosion. Can someone bring a real use case showing groups and modes as orthogonal? (something more substantial than Group1

 - Sebastian, what were the other use cases you had in mind when you wanted the @param approach

#2 keep it open for later
we could reserve the "payload" or "parameter" attribute name and use it for a next rev of this spec.

#3 the string based approach
Sebastian's proposal

@NotNull(params={@Param(key="prio";value="1"),@Param(key="severity";value="3")})
String myfield;

I personally don't like this approach as it is very verbose and totally unsafe. But it has the advantage of allowing parameters very easily.

#4 the interface based approach

(Part of) Gerhard's proposal

interface javax.validation.ValidationParameter {}

//framework classes
interface com.acme.ViolationSeverity extends ValidationParameter {
     FacesMessage.Severity();
     MessageType postfix();
}

class com.acme.WarnSeverity implements ViolationSeverity {
    FacesMessage.Severity() { return acesMessage.SEVERITY_WARN; }
     MessageType postfix() { return MessageType.WARN;}
}

//user code
@NotNull(params=WarnSeverity.class)

Pros:
much cleaner on the client code
type safe ont he client code

Cons:
much more verbose to define a new kind of parameter
untype safe when the value is read by the framework (so is #3) 
    ValidationParameter[] params = constraintViolation.getAnnotation().params(); if (params[0] instanceof ViolationSeverity) {};
it creates a compile time dependency on the targeted framework
no runtime dependency but if the framework is not here, the constraint annotation will not be visible