[hibernate-commits] Hibernate SVN: r19251 - in validator/trunk/hibernate-validator/src: main/java/org/hibernate/validator/constraints and 5 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Apr 20 11:28:19 EDT 2010


Author: hardy.ferentschik
Date: 2010-04-20 11:28:18 -0400 (Tue, 20 Apr 2010)
New Revision: 19251

Added:
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/ScriptAssert.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/ScriptAssertValidator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluator.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluatorFactory.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/package.html
   validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/constraints/impl/ScriptAssertValidatorTest.java
Removed:
   validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/defineconstraints.xml
Modified:
   validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/usingvalidator.xml
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationDescriptor.java
   validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java
   validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages.properties
   validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_de.properties
Log:
HV-292 - Provide a constraint annotation @ScriptAssert


Deleted: validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/defineconstraints.xml
===================================================================
--- validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/defineconstraints.xml	2010-04-20 15:22:58 UTC (rev 19250)
+++ validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/defineconstraints.xml	2010-04-20 15:28:18 UTC (rev 19251)
@@ -1,487 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- $Id$ -->
-<!--
-	~ JBoss, Home of Professional Open Source
-	~ Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
-	~ by the @authors tag. See the copyright.txt in the distribution for a
-	~ full listing of individual contributors.
-	~
-	~ Licensed under the Apache License, Version 2.0 (the "License");
-	~ you may not use this file except in compliance with the License.
-	~ You may obtain a copy of the License at
-	~ http://www.apache.org/licenses/LICENSE-2.0
-	~ Unless required by applicable law or agreed to in writing, software
-	~ distributed under the License is distributed on an "AS IS" BASIS,
-	~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-	~ See the License for the specific language governing permissions and
-	~ limitations under the License.
--->
-<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="validator-defineconstraints">
-  <title>Defining constraints</title>
-
-  <section id="validator-defineconstraints-definition">
-    <title>What is a constraint?</title>
-
-    <para>A constraint is a rule that a given element (field, property or
-    bean) has to comply to. The rule semantic is expressed by an annotation. A
-    constraint usually has some attributes used to parameterize the
-    constraints limits. The constraint applies to the annotated
-    element.</para>
-  </section>
-
-  <section id="foo">
-    <title>Built in constraints</title>
-
-    <para>Hibernate Validator comes with some built-in constraints, which
-    covers most basic data checks. As we'll see later, you're not limited to
-    them, you can literally in a minute write your own constraints.</para>
-
-    <table>
-      <title>Built-in constraints</title>
-
-      <tgroup cols="4">
-        <colspec align="center" />
-
-        <thead>
-          <row>
-            <entry>Annotation</entry>
-
-            <entry>Apply on</entry>
-
-            <entry>Runtime checking</entry>
-
-            <entry>Hibernate Metadata impact</entry>
-          </row>
-        </thead>
-
-        <tbody>
-          <row>
-            <entry>@Length(min=, max=)</entry>
-
-            <entry>property (String)</entry>
-
-            <entry>check if the string length match the range</entry>
-
-            <entry>Column length will be set to max</entry>
-          </row>
-
-          <row>
-            <entry>@Max(value=)</entry>
-
-            <entry>property (numeric or string representation of a
-            numeric)</entry>
-
-            <entry>check if the value is less than or equals to max</entry>
-
-            <entry>Add a check constraint on the column</entry>
-          </row>
-
-          <row>
-            <entry>@Min(value=)</entry>
-
-            <entry>property (numeric or string representation of a
-            numeric)</entry>
-
-            <entry>check if the value is more than or equals to min</entry>
-
-            <entry>Add a check constraint on the column</entry>
-          </row>
-
-          <row>
-            <entry>@NotNull</entry>
-
-            <entry>property</entry>
-
-            <entry>check if the value is not null</entry>
-
-            <entry>Column(s) are not null</entry>
-          </row>
-
-          <row>
-            <entry>@NotEmpty</entry>
-
-            <entry>property</entry>
-
-            <entry>check if the string is not null nor empty. Check if the
-            connection is not null nor empty</entry>
-
-            <entry>Column(s) are not null (for String)</entry>
-          </row>
-
-          <row>
-            <entry>@Past</entry>
-
-            <entry>property (date or calendar)</entry>
-
-            <entry>check if the date is in the past</entry>
-
-            <entry>Add a check constraint on the column</entry>
-          </row>
-
-          <row>
-            <entry>@Future</entry>
-
-            <entry>property (date or calendar)</entry>
-
-            <entry>check if the date is in the future</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@Pattern(regex="regexp", flag=) or @Patterns(
-            {@Pattern(...)} )</entry>
-
-            <entry>property (string)</entry>
-
-            <entry>check if the property match the regular expression given a
-            match flag (see <classname>java.util.regex.Pattern </classname>
-            )</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@Range(min=, max=)</entry>
-
-            <entry>property (numeric or string representation of a
-            numeric)</entry>
-
-            <entry>check if the value is between min and max
-            (included)</entry>
-
-            <entry>Add a check constraint on the column</entry>
-          </row>
-
-          <row>
-            <entry>@Size(min=, max=)</entry>
-
-            <entry>property (array, collection, map)</entry>
-
-            <entry>check if the element size is between min and max
-            (included)</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@AssertFalse</entry>
-
-            <entry>property</entry>
-
-            <entry>check that the method evaluates to false (useful for
-            constraints expressed in code rather than annotations)</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@AssertTrue</entry>
-
-            <entry>property</entry>
-
-            <entry>check that the method evaluates to true (useful for
-            constraints expressed in code rather than annotations)</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@Valid</entry>
-
-            <entry>property (object)</entry>
-
-            <entry>perform validation recursively on the associated object. If
-            the object is a Collection or an array, the elements are validated
-            recursively. If the object is a Map, the value elements are
-            validated recursively.</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@Email</entry>
-
-            <entry>property (String)</entry>
-
-            <entry>check whether the string is conform to the email address
-            specification</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@CreditCardNumber</entry>
-
-            <entry>property (String)</entry>
-
-            <entry>check whether the string is a well formated credit card
-            number (derivative of the Luhn algorithm)</entry>
-
-            <entry>none</entry>
-          </row>
-
-          <row>
-            <entry>@Digits</entry>
-
-            <entry>property (numeric or string representation of a
-            numeric)</entry>
-
-            <entry>check whether the property is a number having up to
-            <literal>integerDigits</literal> integer digits and
-            <literal>fractionalDigits</literal> fractonal digits</entry>
-
-            <entry>define column precision and scale</entry>
-          </row>
-
-          <row>
-            <entry>@EAN</entry>
-
-            <entry>property (string)</entry>
-
-            <entry>check whether the string is a properly formated EAN or
-            UPC-A code</entry>
-
-            <entry>none</entry>
-          </row>
-        </tbody>
-      </tgroup>
-    </table>
-  </section>
-
-  <section id="validator-defineconstraints-error">
-    <title>Error messages</title>
-
-    <para>Hibernate Validator comes with a default set of error messages
-    translated in about ten languages (if yours is not part of it, please sent
-    us a patch). You can override those messages by creating a
-    <filename>ValidatorMessages.properties</filename> or (
-    <filename>ValidatorMessages_loc.properties</filename> ) and override the
-    needed keys. You can even add your own additional set of messages while
-    writing your validator annotations. If Hibernate Validator cannot resolve
-    a key from your resourceBundle nor from ValidatorMessage, it falls back to
-    the default built-in values.</para>
-
-    <para>Alternatively you can provide a
-    <classname>ResourceBundle</classname> while checking programmatically the
-    validation rules on a bean or if you want a completly different
-    interpolation mechanism, you can provide an implementation of
-    <literal>org.hibernate.validator.MessageInterpolator</literal> (check the
-    JavaDoc for more informations).</para>
-  </section>
-
-  <section id="validator-defineconstraints-own">
-    <title>Writing your own constraints</title>
-
-    <para>Extending the set of built-in constraints is extremely easy. Any
-    constraint consists of two pieces: the constraint
-    <emphasis>descriptor</emphasis> (the annotation) and the constraint
-    <emphasis>validator</emphasis> (the implementation class). Here is a
-    simple user-defined descriptor:</para>
-
-    <programlisting role="JAVA" language="JAVA">@ValidatorClass(CapitalizedValidator.class)
- at Target(METHOD)
- at Retention(RUNTIME)
- at Documented
-public @interface Capitalized {
-    CapitalizeType type() default Capitalize.FIRST;
-    String message() default "has incorrect capitalization"
-}        </programlisting>
-
-    <para><literal>type</literal> is a parameter describing how the property
-    should to be capitalized. This is a user parameter fully dependant on the
-    annotation business.</para>
-
-    <para><literal>message</literal> is the default string used to describe
-    the constraint violation and is mandatory. You can hard code the string or
-    you can externalize part/all of it through the Java ResourceBundle
-    mechanism. Parameters values are going to be injected inside the message
-    when the <literal>{parameter}</literal> string is found (in our example
-    <literal>Capitalization is not {type}</literal> would generate
-    <literal>Capitalization is not FIRST</literal> ), externalizing the whole
-    string in <filename>ValidatorMessages.properties</filename> is considered
-    good practice. See <xref linkend="validator-defineconstraints-error" />
-    .</para>
-
-    <programlisting role="JAVA" language="JAVA">@ValidatorClass(CapitalizedValidator.class)
- at Target(METHOD)
- at Retention(RUNTIME)
- at Documented
-public @interface Capitalized {
-    CapitalizeType type() default Capitalize.FIRST;
-    String message() default "{validator.capitalized}";
-}
-
-
-#in ValidatorMessages.properties
-validator.capitalized = <literal>Capitalization is not {type}</literal>
-        </programlisting>
-
-    <para>As you can see the {} notation is recursive.</para>
-
-    <para>To link a descriptor to its validator implementation, we use the
-    <literal>@ValidatorClass</literal> meta-annotation. The validator class
-    parameter must name a class which implements
-    <literal>Validator&lt;ConstraintAnnotation&gt;</literal> .</para>
-
-    <para>We now have to implement the validator (ie. the rule checking
-    implementation). A validation implementation can check the value of the a
-    property (by implementing <literal>PropertyConstraint</literal> ) and/or
-    can modify the hibernate mapping metadata to express the constraint at the
-    database level (by implementing
-    <literal>PersistentClassConstraint</literal> )</para>
-
-    <programlisting role="JAVA" language="JAVA">public class CapitalizedValidator
-        implements Validator&lt;Capitalized&gt;, PropertyConstraint {
-    private CapitalizeType type;
-
-    //part of the Validator&lt;Annotation&gt; contract,
-    //allows to get and use the annotation values
-    public void initialize(Capitalized parameters) {
-        type = parameters.type();
-    }
-
-    //part of the property constraint contract
-    public boolean isValid(Object value) {
-        if (value==null) return true;
-        if ( !(value instanceof String) ) return false;
-        String string = (String) value;
-        if (type == CapitalizeType.ALL) {
-            return string.equals( string.toUpperCase() );
-        }
-        else {
-            String first = string.substring(0,1);
-            return first.equals( first.toUpperCase();
-        }
-    }
-}        </programlisting>
-
-    <para>The <literal>isValid()</literal> method should return false if the
-    constraint has been violated. For more examples, refer to the built-in
-    validator implementations.</para>
-
-    <para>We only have seen property level validation, but you can write a
-    Bean level validation annotation. Instead of receiving the return instance
-    of a property, the bean itself will be passed to the validator. To
-    activate the validation checking, just annotated the bean itself instead.
-    A small sample can be found in the unit test suite.</para>
-
-    <para>If your constraint can be applied multiple times (with different
-    parameters) on the same property or type, you can use the following
-    annotation form:</para>
-
-    <programlisting role="JAVA" language="JAVA">@Target(METHOD)
- at Retention(RUNTIME)
- at Documented
-<emphasis role="bold">public @interface Patterns {</emphasis>
-    Pattern[] value();
-}
-
- at Target(METHOD)
- at Retention(RUNTIME)
- at Documented
- at ValidatorClass(PatternValidator.class)
-public @interface Pattern {
-    String regexp();
-}</programlisting>
-
-    <para>Basically an annotation containing the value attribute as an array
-    of validator annotations.</para>
-  </section>
-
-  <section>
-    <title>Annotating your domain model</title>
-
-    <para>Since you are already familiar with annotations now, the syntax
-    should be very familiar</para>
-
-    <programlisting role="JAVA" language="JAVA">public class Address {
-    private String line1;
-    private String line2;
-    private String zip;
-    private String state;
-    private String country;
-    private long id;
-
-    // a not null string of 20 characters maximum
-    @Length(max=20)
-    @NotNull
-    public String getCountry() {
-        return country;
-    }
-
-    // a non null string
-    @NotNull
-    public String getLine1() {
-        return line1;
-    }
-
-    //no constraint
-    public String getLine2() {
-        return line2;
-    }
-
-    // a not null string of 3 characters maximum
-    @Length(max=3) @NotNull
-    public String getState() {
-        return state;
-    }
-
-    // a not null numeric string of 5 characters maximum
-    // if the string is longer, the message will
-    //be searched in the resource bundle at key 'long'
-    @Length(max=5, message="{long}")
-    @Pattern(regex="[0-9]+")
-    @NotNull
-    public String getZip() {
-        return zip;
-    }
-
-    // should always be true
-    @AssertTrue
-    public boolean isValid() {
-        return true;
-    }
-
-    // a numeric between 1 and 2000
-    @Id @Min(1)
-    @Range(max=2000)
-    public long getId() {
-        return id;
-    }
-}        </programlisting>
-
-    <para>While the example only shows public property validation, you can
-    also annotate fields of any kind of visibility</para>
-
-    <programlisting role="JAVA" language="JAVA">@MyBeanConstraint(max=45
-public class Dog {
-    @AssertTrue private boolean isMale;
-    @NotNull protected String getName() { ... };
-    ...
-}        </programlisting>
-
-    <para>You can also annotate interfaces. Hibernate Validator will check all
-    superclasses and interfaces extended or implemented by a given bean to
-    read the appropriate validator annotations.</para>
-
-    <programlisting role="JAVA" language="JAVA">public interface Named {
-    @NotNull String getName();
-    ...
-}
-
-public class Dog implements Named {
-
-    @AssertTrue private boolean isMale;
-
-    public String getName() { ... };
-
-}
-        </programlisting>
-
-    <para>The name property will be checked for nullity when the Dog bean is
-    validated.</para>
-  </section>
-</chapter>

Modified: validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/usingvalidator.xml
===================================================================
--- validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/usingvalidator.xml	2010-04-20 15:22:58 UTC (rev 19250)
+++ validator/trunk/hibernate-validator/src/main/docbook/en-US/modules/usingvalidator.xml	2010-04-20 15:28:18 UTC (rev 19251)
@@ -1182,7 +1182,7 @@
             <classname>int</classname>, <classname>long</classname> and the
             respective wrappers of the primitive types.</entry>
 
-            <entry>Check whether the annotated value is higher than or equal
+            <entry>Checks whether the annotated value is higher than or equal
             to the specified minimum.</entry>
 
             <entry>Add a check constraint on the column.</entry>
@@ -1224,7 +1224,7 @@
             <entry>field/property. Supported types are String, Collection, Map
             and arrays.</entry>
 
-            <entry>Check whether is annoated element is not
+            <entry>Check whether the annotated element is not
             <constant>null</constant> nor empty.</entry>
 
             <entry>none</entry>
@@ -1264,8 +1264,9 @@
 
             <entry>field/property. Needs to be a string.</entry>
 
-            <entry>Check if the annotated string match the regular expression
-            <parameter>regex</parameter>.</entry>
+            <entry>Checks if the annotated string matches the regular
+            expression <parameter>regex</parameter> considering the given flag
+            <parameter>match</parameter>.</entry>
 
             <entry>none</entry>
           </row>
@@ -1305,6 +1306,27 @@
           </row>
 
           <row>
+            <entry>@ScriptAssert(lang=, script=, alias=)</entry>
+
+            <entry>no</entry>
+
+            <entry>type</entry>
+
+            <entry>Checks whether the given script can successfully be
+            evaluated against the annotated element. In order to use this
+            constraint, an implementation of the Java Scripting API as defined
+            by JSR 223 ("Scripting for the Java<superscript>TM</superscript>
+            Platform") must part of the class path. This is automatically the
+            case when running on Java 6. For older Java versions, the JSR 223
+            RI can be added manually to the class path.The expressions to be
+            evaluated can be written in any scripting or expression language,
+            for which a JSR 223 compatible engine can be found in the class
+            path.</entry>
+
+            <entry>none</entry>
+          </row>
+
+          <row>
             <entry>@URL(protocol=, host=, port=)</entry>
 
             <entry>no</entry>
@@ -1326,10 +1348,13 @@
 
             <entry>yes</entry>
 
-            <entry>field/property</entry>
+            <entry>field/property. Any non-primitive types are
+            supported.</entry>
 
-            <entry>Perform validation recursively on the associated
-            object.</entry>
+            <entry>Performs validation recursively on the associated object. If
+            the object is a collection or an array, the elements are validated
+            recursively. If the object is a map, the value elements are
+            validated recursively.</entry>
 
             <entry>none</entry>
           </row>

Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/ScriptAssert.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/ScriptAssert.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/ScriptAssert.java	2010-04-20 15:28:18 UTC (rev 19251)
@@ -0,0 +1,139 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.constraints;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngineManager;
+import javax.validation.Constraint;
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.Payload;
+
+import org.hibernate.validator.constraints.impl.ScriptAssertValidator;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * <p>
+ * A class-level constraint, that evaluates a script expression against the
+ * annotated element. This constraint can be used to implement validation
+ * routines, that depend on multiple attributes of the annotated element.
+ * </p>
+ * <p>
+ * For evaluation of expressions the Java Scripting API as defined by <a
+ * href="http://jcp.org/en/jsr/detail?id=223">JSR 223</a>
+ * ("Scripting for the Java<sup>TM</sup> Platform") is used. Therefore an
+ * implementation of that API must part of the class path. This is automatically
+ * the case when running on Java 6. For older Java versions, the JSR 223 RI can
+ * be added manually to the class path.
+ * </p>
+ * The expressions to be evaluated can be written in any scripting or expression
+ * language, for which a JSR 223 compatible engine can be found in the class
+ * path. The following listing shows an example using the JavaScript engine,
+ * which comes with Java 6: </p>
+ * <p/>
+ * <pre>
+ * &#064;ScriptAssert(lang = &quot;javascript&quot;, script = &quot;_this.startDate.before(_this.endDate)&quot;)
+ * public class CalendarEvent {
+ * <p/>
+ * 	private Date startDate;
+ * <p/>
+ * 	private Date endDate;
+ * <p/>
+ * 	//...
+ * <p/>
+ * }
+ * </pre>
+ * <p>
+ * Using a real expression language in conjunction with a shorter object alias allows
+ * for very compact expressions:
+ * </p>
+ * <pre>
+ * &#064;ScriptAssert(lang = &quot;jexl&quot;, script = &quot;_.startDate &lt; _.endDate&quot;, alias = &quot;_&quot;)
+ * public class CalendarEvent {
+ * <p/>
+ * 	private Date startDate;
+ * <p/>
+ * 	private Date endDate;
+ * <p/>
+ * 	//...
+ * <p/>
+ * }
+ * </pre>
+ * <p>
+ * Accepts any type.
+ * </p>
+ *
+ * @author Gunnar Morling
+ */
+ at Target({ TYPE })
+ at Retention(RUNTIME)
+ at Constraint(validatedBy = ScriptAssertValidator.class)
+ at Documented
+public @interface ScriptAssert {
+
+	String message() default "{org.hibernate.validator.constraints.ScriptAssert.message}";
+
+	Class<?>[] groups() default { };
+
+	Class<? extends Payload>[] payload() default { };
+
+	/**
+	 * @return The name of the script language used by this constraint as
+	 *         expected by the JSR 223 {@link ScriptEngineManager}. A
+	 *         {@link ConstraintDeclarationException} will be thrown upon script
+	 *         evaluation, if no engine for the given language could be found.
+	 */
+	String lang();
+
+	/**
+	 * @return The script to be executed. The script must return
+	 *         <code>Boolean.TRUE</code>, if the annotated element could
+	 *         successfully be validated, otherwise <code>Boolean.FALSE</code>.
+	 *         Returning null or any type other than Boolean will cause a
+	 *         {@link ConstraintDeclarationException} upon validation. Any
+	 *         exception occurring during script evaluation will be wrapped into
+	 *         a ConstraintDeclarationException, too. Within the script, the
+	 *         validated object can be accessed from the {@link ScriptContext
+	 *         script context} using the name specified in the
+	 *         <code>alias</code> attribute.
+	 */
+	String script();
+
+	/**
+	 * @return The name, under which the annotated element shall be registered
+	 *         within the script context. Defaults to "_this".
+	 */
+	String alias() default "_this";
+
+	/**
+	 * Defines several @ScriptAssert annotations on the same element.
+	 *
+	 * @author Gunnar Morling
+	 * @see ScriptAssert
+	 */
+	@Target({ TYPE })
+	@Retention(RUNTIME)
+	@Documented
+	public @interface List {
+		ScriptAssert[] value();
+	}
+}


Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/ScriptAssert.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/ScriptAssertValidator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/ScriptAssertValidator.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/ScriptAssertValidator.java	2010-04-20 15:28:18 UTC (rev 19251)
@@ -0,0 +1,69 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.constraints.impl;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import org.hibernate.validator.constraints.ScriptAssert;
+import org.hibernate.validator.constraints.impl.scriptassert.ScriptEvaluator;
+import org.hibernate.validator.constraints.impl.scriptassert.ScriptEvaluatorFactory;
+
+/**
+ * Validator for the {@link ScriptAssert} constraint annotation.
+ *
+ * @author Gunnar Morling.
+ */
+public class ScriptAssertValidator implements ConstraintValidator<ScriptAssert, Object> {
+
+	private String script;
+
+	private String languageName;
+
+	private String alias;
+
+	public void initialize(ScriptAssert constraintAnnotation) {
+
+		validateParameters( constraintAnnotation );
+
+		this.script = constraintAnnotation.script();
+		this.languageName = constraintAnnotation.lang();
+		this.alias = constraintAnnotation.alias();
+	}
+
+	public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
+
+		ScriptEvaluator scriptEvaluator = ScriptEvaluatorFactory.getInstance()
+				.getScriptEvaluatorByLanguageName( languageName );
+
+		return scriptEvaluator.evaluate( script, value, alias );
+	}
+
+	private void validateParameters(ScriptAssert constraintAnnotation) {
+
+		if ( constraintAnnotation.script().isEmpty() ) {
+			throw new IllegalArgumentException( "The parameter \"script\" must not be empty." );
+		}
+		if ( constraintAnnotation.lang().isEmpty() ) {
+			throw new IllegalArgumentException( "The parameter \"lang\" must not be empty." );
+		}
+		if ( constraintAnnotation.alias().isEmpty() ) {
+			throw new IllegalArgumentException( "The parameter \"alias\" must not be empty." );
+		}
+	}
+}


Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/ScriptAssertValidator.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluator.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluator.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluator.java	2010-04-20 15:28:18 UTC (rev 19251)
@@ -0,0 +1,108 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,  
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.constraints.impl.scriptassert;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import javax.validation.ConstraintDeclarationException;
+
+/**
+ * A wrapper around JSR 223 {@link ScriptEngine}s. This class is thread-safe.
+ *
+ * @author Gunnar Morling
+ */
+public class ScriptEvaluator {
+
+	private final ScriptEngine engine;
+
+	/**
+	 * Creates a new script executor.
+	 *
+	 * @param engine The engine to be wrapped.
+	 */
+	public ScriptEvaluator(ScriptEngine engine) {
+		this.engine = engine;
+	}
+
+	/**
+	 * Makes the given object available in then engine-scoped script context and executes the given script.
+	 * The execution of the script happens either synchronized or unsynchronized, depending on the engine's
+	 * threading abilities.
+	 *
+	 * @param script The script to be executed.
+	 * @param obj The object to be put into the context.
+	 * @param objectAlias The name under which the given object shall be put into the context.
+	 *
+	 * @return The script's result.
+	 *
+	 * @throws ConstraintDeclarationException In case of any errors during script execution or if the script
+	 *                                        returned null or another type than Boolean.
+	 */
+	public boolean evaluate(String script, Object obj, String objectAlias) {
+
+		if ( engineAllowsParallelAccessFromMultipleThreads() ) {
+			return doEvaluate( script, obj, objectAlias );
+		}
+		else {
+			synchronized ( engine ) {
+				return doEvaluate( script, obj, objectAlias );
+			}
+		}
+	}
+
+	private boolean doEvaluate(String script, Object obj, String objectAlias) {
+
+		engine.put( objectAlias, obj );
+
+		Object evaluationResult;
+
+		try {
+			evaluationResult = engine.eval( script );
+		}
+		catch ( ScriptException e ) {
+			throw new ConstraintDeclarationException(
+					"Error during execution of script \"" + script + "\" occured.", e
+			);
+		}
+
+		if ( evaluationResult == null ) {
+			throw new ConstraintDeclarationException( "Script \"" + script + "\" returned null, but must return either true or false." );
+		}
+
+		if ( !( evaluationResult instanceof Boolean ) ) {
+			throw new ConstraintDeclarationException(
+					"Script \"" + script + "\" returned " + evaluationResult + " (of type " + evaluationResult.getClass()
+							.getCanonicalName() + "), but must return either true or false."
+			);
+		}
+
+		return Boolean.TRUE.equals( evaluationResult );
+	}
+
+	/**
+	 * Checks, whether the given engine is thread-safe or not.
+	 *
+	 * @return True, if the given engine is thread-safe, false otherwise.
+	 */
+	private boolean engineAllowsParallelAccessFromMultipleThreads() {
+
+		String threadingType = ( String ) engine.getFactory().getParameter( "THREADING" );
+
+		return "THREAD-ISOLATED".equals( threadingType ) || "STATELESS".equals( threadingType );
+	}
+}


Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluator.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluatorFactory.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluatorFactory.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluatorFactory.java	2010-04-20 15:28:18 UTC (rev 19251)
@@ -0,0 +1,105 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,  
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.constraints.impl.scriptassert;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.validation.ConstraintDeclarationException;
+
+/**
+ * Factory responsible for the creation of {@link ScriptEvaluator}s. This
+ * class is thread-safe.
+ *
+ * @author Gunnar Morling
+ */
+public class ScriptEvaluatorFactory {
+
+	/**
+	 * A reference with an instance of this factory. Allows the factory to be reused several times, but can be GC'ed if required.
+	 */
+	private static Reference<ScriptEvaluatorFactory> INSTANCE = new SoftReference<ScriptEvaluatorFactory>( new ScriptEvaluatorFactory() );
+
+	/**
+	 * A cache of script executors (keyed by language name).
+	 */
+	private ConcurrentMap<String, ScriptEvaluator> scriptExecutorCache = new ConcurrentHashMap<String, ScriptEvaluator>();
+
+	private ScriptEvaluatorFactory() {
+	}
+
+	/**
+	 * Retrieves an instance of this factory.
+	 *
+	 * @return A script evaluator factory. Never null.
+	 */
+	public static synchronized ScriptEvaluatorFactory getInstance() {
+
+		ScriptEvaluatorFactory theValue = INSTANCE.get();
+
+		if ( theValue == null ) {
+			theValue = new ScriptEvaluatorFactory();
+			INSTANCE = new SoftReference<ScriptEvaluatorFactory>( theValue );
+		}
+
+		return theValue;
+	}
+
+	/**
+	 * Retrieves a script executor for the given language.
+	 *
+	 * @param languageName The name of a scripting language as expected by {@link ScriptEngineManager#getEngineByName(String)}.
+	 *
+	 * @return A script executor for the given language. Never null.
+	 *
+	 * @throws ConstraintDeclarationException In case no JSR 223 compatible engine for the given language could be found.
+	 */
+	public ScriptEvaluator getScriptEvaluatorByLanguageName(String languageName) {
+
+		if ( !scriptExecutorCache.containsKey( languageName ) ) {
+
+			ScriptEvaluator scriptExecutor = createNewScriptEvaluator( languageName );
+			scriptExecutorCache.putIfAbsent( languageName, scriptExecutor );
+		}
+
+		return scriptExecutorCache.get( languageName );
+	}
+
+	/**
+	 * Creates a new script executor for the given language.
+	 *
+	 * @param languageName A JSR 223 language name.
+	 *
+	 * @return A newly created script executor for the given language.
+	 */
+	private ScriptEvaluator createNewScriptEvaluator(String languageName) {
+
+		ScriptEngine engine = new ScriptEngineManager().getEngineByName( languageName );
+
+		if ( engine == null ) {
+			throw new ConstraintDeclarationException(
+					"No JSR 223 script engine found for language \"" + languageName + "\"."
+			);
+		}
+
+		return new ScriptEvaluator( engine );
+	}
+}


Property changes on: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/ScriptEvaluatorFactory.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/package.html
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/package.html	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/constraints/impl/scriptassert/package.html	2010-04-20 15:28:18 UTC (rev 19251)
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+    <!--
+
+  JBoss, Home of Professional Open Source
+  Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+  by the @authors tag. See the copyright.txt in the distribution for a
+  full listing of individual contributors.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  http://www.apache.org/licenses/LICENSE-2.0
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+</head>
+<body>
+This package contains classes related to the evaluation of the @ScriptAssert constraint.
+</body>
+</html>

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationDescriptor.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationDescriptor.java	2010-04-20 15:22:58 UTC (rev 19250)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationDescriptor.java	2010-04-20 15:28:18 UTC (rev 19251)
@@ -1,7 +1,7 @@
 // $Id$
 /*
 * JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
@@ -39,6 +39,31 @@
 
 	private final Map<String, Object> elements = new HashMap<String, Object>();
 
+	/**
+	 * Returns a new descriptor for the given annotation type.
+	 * 
+	 * @param <S> The type of the annotation.
+	 * @param annotationType The annotation's class.
+	 * 
+	 * @return A new descriptor for the given annotation type.
+	 */
+	public static <S extends Annotation> AnnotationDescriptor<S> getInstance(Class<S> annotationType) {
+		return new AnnotationDescriptor<S>(annotationType);
+	}
+	
+	/**
+	 * Returns a new descriptor for the given annotation type.
+	 * 
+	 * @param <S> The type of the annotation.
+	 * @param annotationType The annotation's class.
+	 * @param elements A map with attribute values for the annotation to be created.
+	 * 
+	 * @return A new descriptor for the given annotation type.
+	 */
+	public static <S extends Annotation> AnnotationDescriptor<S> getInstance(Class<S> annotationType, Map<String, Object> elements) {
+		return new AnnotationDescriptor<S>(annotationType, elements);
+	}
+	
 	public AnnotationDescriptor(Class<T> annotationType) {
 		this.type = annotationType;
 	}

Modified: validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java
===================================================================
--- validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java	2010-04-20 15:22:58 UTC (rev 19250)
+++ validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java	2010-04-20 15:28:18 UTC (rev 19251)
@@ -1,7 +1,7 @@
 // $Id$
 /*
 * JBoss, Home of Professional Open Source
-* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
@@ -89,7 +89,7 @@
 			}
 		}
 		if ( processedValuesFromDescriptor != descriptor.numberOfElements() ) {
-			throw new RuntimeException( "Trying to instantiate " + annotationType + " with unknown paramters." );
+			throw new RuntimeException( "Trying to instantiate " + annotationType + " with unknown parameters." );
 		}
 		return result;
 	}

Modified: validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages.properties
===================================================================
--- validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages.properties	2010-04-20 15:22:58 UTC (rev 19250)
+++ validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages.properties	2010-04-20 15:28:18 UTC (rev 19251)
@@ -19,5 +19,5 @@
 org.hibernate.validator.constraints.NotEmpty.message=may not be empty
 org.hibernate.validator.constraints.Range.message=must be between {min} and {max}
 org.hibernate.validator.constraints.URL.message=must be a valid URL
-org.hibernate.validator.constraints.CreditCardNumber.message=Invalid credit card number
-
+org.hibernate.validator.constraints.CreditCardNumber.message=invalid credit card number
+org.hibernate.validator.constraints.ScriptAssert.message=script expression "{script}" didn't evaluate to true

Modified: validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_de.properties
===================================================================
--- validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_de.properties	2010-04-20 15:22:58 UTC (rev 19250)
+++ validator/trunk/hibernate-validator/src/main/resources/org/hibernate/validator/ValidationMessages_de.properties	2010-04-20 15:28:18 UTC (rev 19251)
@@ -18,4 +18,5 @@
 org.hibernate.validator.constraints.NotEmpty.message=kann nicht leer sein
 org.hibernate.validator.constraints.Range.message=muss zwischen {min} und {max} liegen
 org.hibernate.validator.constraints.URL.message=muss eine g\u00FCltige URL sein
-org.hibernate.validator.constraints.CreditCardNumber.message=Ung\u00FCltige Kreditkartennummer
\ No newline at end of file
+org.hibernate.validator.constraints.CreditCardNumber.message=ung\u00FCltige Kreditkartennummer
+org.hibernate.validator.constraints.ScriptAssert.message=Skriptausdruck "{script}" muss true zur\u00FCckliefern

Added: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/constraints/impl/ScriptAssertValidatorTest.java
===================================================================
--- validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/constraints/impl/ScriptAssertValidatorTest.java	                        (rev 0)
+++ validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/constraints/impl/ScriptAssertValidatorTest.java	2010-04-20 15:28:18 UTC (rev 19251)
@@ -0,0 +1,202 @@
+// $Id$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2010, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.constraints.impl;
+
+import java.util.Date;
+import java.util.GregorianCalendar;
+import javax.validation.ConstraintDeclarationException;
+import javax.validation.ConstraintValidator;
+
+import org.testng.annotations.Test;
+
+import org.hibernate.validator.constraints.ScriptAssert;
+import org.hibernate.validator.util.annotationfactory.AnnotationDescriptor;
+import org.hibernate.validator.util.annotationfactory.AnnotationFactory;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Unit test for {@link ScriptAssertValidator}.
+ *
+ * @author Gunnar Morling
+ */
+public class ScriptAssertValidatorTest {
+
+	@Test
+	public void scriptEvaluatesToTrue() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "javascript", "true" );
+
+		assertTrue( validator.isValid( new Object(), null ) );
+	}
+
+	@Test
+	public void scriptEvaluatesToFalse() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "javascript", "false" );
+
+		assertFalse( validator.isValid( new Object(), null ) );
+	}
+
+	@Test
+	public void scriptExpressionReferencingAnnotatedObject() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator(
+				"javascript", "_this.startDate.before(_this.endDate)"
+		);
+
+		Date startDate = new GregorianCalendar( 2009, 8, 20 ).getTime();
+		Date endDate = new GregorianCalendar( 2009, 8, 21 ).getTime();
+
+		assertTrue( validator.isValid( new CalendarEvent( startDate, endDate ), null ) );
+		assertFalse( validator.isValid( new CalendarEvent( endDate, startDate ), null ) );
+	}
+
+	@Test
+	public void scriptExpressionUsingCustomizedAlias() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator(
+				"javascript", "_.startDate.before(_.endDate)", "_"
+		);
+
+		Date startDate = new GregorianCalendar( 2009, 8, 20 ).getTime();
+		Date endDate = new GregorianCalendar( 2009, 8, 21 ).getTime();
+
+		assertFalse( validator.isValid( new CalendarEvent( endDate, startDate ), null ) );
+	}
+
+	@Test(expectedExceptions = IllegalArgumentException.class)
+	public void emptyLanguageNameRaisesException() throws Exception {
+
+		getInitializedValidator( "", "script" );
+	}
+
+	@Test(expectedExceptions = IllegalArgumentException.class)
+	public void emptyScriptRaisesException() throws Exception {
+
+		getInitializedValidator( "lang", "" );
+	}
+
+	@Test(expectedExceptions = IllegalArgumentException.class)
+	public void emptyAliasRaisesException() throws Exception {
+
+		getInitializedValidator( "lang", "script", "" );
+	}
+
+	@Test(expectedExceptions = ConstraintDeclarationException.class)
+	public void unknownLanguageNameRaisesException() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "foo", "script" );
+
+		validator.isValid( new Object(), null );
+	}
+
+	@Test(expectedExceptions = ConstraintDeclarationException.class)
+	public void illegalScriptExpressionRaisesException() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "javascript", "foo" );
+
+		validator.isValid( new Object(), null );
+	}
+
+	@Test(expectedExceptions = ConstraintDeclarationException.class)
+	public void scriptExpressionReturningNullRaisesException() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator( "javascript", "null" );
+
+		validator.isValid( new Object(), null );
+	}
+
+	@Test(expectedExceptions = ConstraintDeclarationException.class)
+	public void scriptExpressionReturningNoBooleanRaisesException() throws Exception {
+
+		ConstraintValidator<ScriptAssert, Object> validator = getInitializedValidator(
+				"javascript", "new java.util.Date()"
+		);
+
+		validator.isValid( new Object(), null );
+	}
+
+	/**
+	 * Returns a {@link ScriptAssertValidator} initialized with a {@link ScriptAssert} with the given values.
+	 */
+	private ConstraintValidator<ScriptAssert, Object> getInitializedValidator(String lang, String script, String name) {
+
+		ConstraintValidator<ScriptAssert, Object> validator = new ScriptAssertValidator();
+		validator.initialize( getScriptAssert( lang, script, name ) );
+
+		return validator;
+	}
+
+	/**
+	 * Returns a {@link ScriptAssertValidator} initialized with a {@link ScriptAssert} with the given values.
+	 */
+	private ConstraintValidator<ScriptAssert, Object> getInitializedValidator(String lang, String script) {
+
+		ConstraintValidator<ScriptAssert, Object> validator = new ScriptAssertValidator();
+		validator.initialize( getScriptAssert( lang, script, null ) );
+
+		return validator;
+	}
+
+	/**
+	 * Returns a {@link ScriptAssert} initialized with the given values.
+	 */
+	private ScriptAssert getScriptAssert(String lang, String script, String name) {
+
+		AnnotationDescriptor<ScriptAssert> descriptor = AnnotationDescriptor.getInstance( ScriptAssert.class );
+
+		descriptor.setValue( "lang", lang );
+		descriptor.setValue( "script", script );
+		if ( name != null ) {
+			descriptor.setValue( "alias", name );
+		}
+
+		return AnnotationFactory.create( descriptor );
+	}
+
+	/**
+	 * An exemplary model class used in tests.
+	 *
+	 * @author Gunnar Morling
+	 */
+	private static class CalendarEvent {
+
+		private Date startDate;
+
+		private Date endDate;
+
+		public CalendarEvent(Date startDate, Date endDate) {
+
+			this.startDate = startDate;
+			this.endDate = endDate;
+		}
+
+		@SuppressWarnings("unused")
+		public Date getStartDate() {
+			return startDate;
+		}
+
+		@SuppressWarnings("unused")
+		public Date getEndDate() {
+			return endDate;
+		}
+
+	}
+}


Property changes on: validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/constraints/impl/ScriptAssertValidatorTest.java
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the hibernate-commits mailing list