This discussion is archived
11 Replies Latest reply: Dec 7, 2012 6:10 AM by 960507 RSS

JSR-303 annotations and runtime derived validation messages (?)

jmsjr Newbie
Currently Being Moderated
I have a need to have the same annotation used in multiple fields / properties, but the validation message to be slightly different which depends on another property, or potentially the lable associated with the input field.

To bettter illustrate, suppose I have a @NotFuture annotation ( Why the standard JSR-303 annotation does not even provide this, which seems to be required in almost all projects that I use, is a different story ), as below:
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import javax.validation.constraints.Future;

import org.hibernate.validator.constraints.CompositionType;
import org.hibernate.validator.constraints.ConstraintComposition;

/**
 * The annotated element must be a date that is not in the future and must not be null.
 * Because this is simply a composition from @Future, this therefore supports 
 * the same data-types as @Future
 */
@ConstraintComposition(CompositionType.ALL_FALSE)
@Future
@ReportAsSingleViolation
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {})
public @interface NotFutureNotNull {
     public abstract String message() default "{constraints.notFutureNotNull.message}";
     public abstract Class<?>[] groups() default { };
     public abstract Class<? extends Payload>[] payload() default { };     
}
Then one of the properties in my backing bean is annotated as such:
     @NotFuture(message="Notification Date cannot be a future date")
     private Date     notificationDate;
All good and fine, JSF will show the message as shown above when it goes through the validation lifecycle and rendered back to the page.
Now I sort of wanted to achieve something like the one below, if it is possible at all:
     @NotFuture(message="#{incidentLabel} cannot be a future date")
     private Date     incidentDate;
The intention is that the message is determined at runtime, as the {incidentLabel} is really derived from another property ( e.g. an incidentType ). Is this even possible ? If not, does this mean we cannot really use JSR-303 annotation when we need a run-time derived validation message ?
  • 1. Re: JSR-303 annotations and runtime derived validation messages (?)
    r035198x Pro
    Currently Being Moderated
    You put the messages in a ValidationMessages.properties file and put it (and its locale variants) at the root of the classpath (src/main/resources for maven projects) and use {keyName} to access the messages in the annotation message value. This is all jsr 303 and so should not be mixed/confused with JSF constructs.
  • 2. Re: JSR-303 annotations and runtime derived validation messages (?)
    jmsjr Newbie
    Currently Being Moderated
    r035198x wrote:
    You put the messages in a ValidationMessages.properties file and put it (and its locale variants) at the root of the classpath (src/main/resources for maven projects) and use {keyName} to access the messages in the annotation message value. This is all jsr 303 and so should not be mixed/confused with JSF constructs.
    I am aware of the ValidationMessage.properties file. I guess what I am after or asking is if it is possible to supply or use an EL expression within the the message itself for a JSR303 validation, as I have not seen one myself. Not seeing one may not mean it is not supported, just that I have not seen one .. and hence, the question.
  • 3. Re: JSR-303 annotations and runtime derived validation messages (?)
    r035198x Pro
    Currently Being Moderated
    jmsjr wrote:
    >
    I am aware of the ValidationMessage.properties file. I guess what I am after or asking is if it is possible to supply or use an EL expression within the the message itself for a JSR303 validation, as I have not seen one myself. Not seeing one may not mean it is not supported, just that I have not seen one .. and hence, the question.
    JSR 303 is separate from JSF and so it doesn't understand JSF constructs like JSF EL.
  • 4. Re: JSR-303 annotations and runtime derived validation messages (?)
    r035198x Pro
    Currently Being Moderated
    I would try writing a custom MessageResolver implementation that uses the message keys to evaluate the JSF EL expressions.
  • 5. Re: JSR-303 annotations and runtime derived validation messages (?)
    jmsjr Newbie
    Currently Being Moderated
    r035198x wrote:
    jmsjr wrote:
    >
    I am aware of the ValidationMessage.properties file. I guess what I am after or asking is if it is possible to supply or use an EL expression within the the message itself for a JSR303 validation, as I have not seen one myself. Not seeing one may not mean it is not supported, just that I have not seen one .. and hence, the question.
    JSR 303 is separate from JSF and so it doesn't understand JSF constructs like JSF EL.
    That answers my question then. Bugger !
  • 6. Re: JSR-303 annotations and runtime derived validation messages (?)
    jmsjr Newbie
    Currently Being Moderated
    r035198x wrote:
    I would try writing a custom MessageResolver implementation that uses the message keys to evaluate the JSF EL expressions.
    Are you referring to javax.validation.MessageInterpolater instead ?
  • 7. Re: JSR-303 annotations and runtime derived validation messages (?)
    r035198x Pro
    Currently Being Moderated
    jmsjr wrote:
    r035198x wrote:
    I would try writing a custom MessageResolver implementation that uses the message keys to evaluate the JSF EL expressions.
    Are you referring to javax.validation.MessageInterpolater instead ?
    Yes that. Opened the wrong (much earlier) version.
  • 8. Re: JSR-303 annotations and runtime derived validation messages (?)
    905019 Newbie
    Currently Being Moderated
    You could also do it straight in the validator implementation. Override the default message and build a custom one. Since it's a JSF request, the FacesContext should be available and you could use resolving. I don't know what payload you could pass along in the validation annotation itself.
  • 9. Re: JSR-303 annotations and runtime derived validation messages (?)
    jmsjr Newbie
    Currently Being Moderated
    Nik wrote:
    You could also do it straight in the validator implementation. Override the default message and build a custom one. Since it's a JSF request, the FacesContext should be available and you could use resolving. I don't know what payload you could pass along in the validation annotation itself.
    Here's what I have done and it works great!
    import java.util.Locale;
    
    import javax.faces.context.FacesContext;
    import javax.validation.MessageInterpolator;
    import javax.validation.Validation;
    
    public class ELMessageInterpolator implements MessageInterpolator {
         
         private final MessageInterpolator delegate;
         
         public ELMessageInterpolator() {
              delegate = Validation
                   .byDefaultProvider()
                   .configure()
                   .getDefaultMessageInterpolator();
         }
         
         private String replaceExpressions(String messageTemplate) {
              FacesContext context = FacesContext.getCurrentInstance();
              String message = context
                   .getApplication()
                   .evaluateExpressionGet(context, messageTemplate, String.class);
              return message;
         }
    
         @Override
         public String interpolate(String messageTemplate, Context context) {
              String message = delegate.interpolate(messageTemplate, context);
              return replaceExpressions( message );
         }
    
         @Override
         public String interpolate(String messageTemplate, Context context, Locale locale) {
              String message = delegate.interpolate(messageTemplate, context, locale);
              return replaceExpressions( message );
         }
    
    }
    An example usage:
    @ManagedBean
    @ViewScoped
    public class ContactDTO implements Serializable, Cloneable {
    
         @AssertTrue(message="Some documents for #{aContactDTO.contact.name.title} #{aContactDTO.contact.name.givenName} #{aContactDTO.contact.name.familyName} have missing information")
         public boolean areDocumentsValid() { ... }
    }
    The output from <h:messages/> or <rich:messages/> that I get, used in conjunction with <rich:graphValidator/>, is like:
    Some documents for Mrs. Jane Smith have missing information
    .. where the names full name is interpolated
  • 10. Re: JSR-303 annotations and runtime derived validation messages (?)
    r035198x Pro
    Currently Being Moderated
    Nice and simple, I thought you would CDI inject an interface and provide the JSF implementation in a separate class but that's only helpful if you are already localizing your JSF API interactions in one place.
  • 11. Re: JSR-303 annotations and runtime derived validation messages (?)
    960507 Newbie
    Currently Being Moderated
    That looks like a nice feature request for JSF.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points