/** Test that static constraints work */
  @SuppressWarnings("rawtypes")
  public void testNullableConstraint() throws Exception {
    String bookClassSource =
        "package org.codehaus.groovy.grails.validation\n"
            + "class Book {\n"
            + "   Long id\n"
            + "   Long version\n"
            + "   String title\n"
            + "   String description\n"
            + "   Author author\n"
            + "   Author assistent\n"
            + "   Set chapters\n"
            + "   Map remarks\n"
            + "   static hasMany = [chapters:Chapter]\n"
            + "   static constraints = {\n"
            + "      description(nullable: true)\n"
            + "      assistent(nullable: true)\n"
            + "   }\n"
            + "}\n"
            + "class Author {\n"
            + "   Long id\n"
            + "   Long version\n"
            + "   String name\n"
            + "}\n"
            + "class Chapter {\n"
            + "   Long id\n"
            + "   Long version\n"
            + "   String text\n"
            + "}";

    GroovyClassLoader gcl = new GroovyClassLoader();

    DefaultGrailsDomainClass bookClass =
        new DefaultGrailsDomainClass(gcl.parseClass(bookClassSource, "Book"));

    Map constraints = bookClass.getConstrainedProperties();
    Constrained p = (Constrained) constraints.get("title");
    assertFalse("Title property should be required", p.isNullable());
    p = (Constrained) constraints.get("description");
    assertTrue("Description property should be optional", p.isNullable());
    p = (Constrained) constraints.get("author");
    assertFalse("Author property should be required", p.isNullable());
    p = (Constrained) constraints.get("assistent");
    assertTrue("Assistent property should be optional", p.isNullable());
    // Test that Collections and Maps are nullable by default
    p = (Constrained) constraints.get("chapters");
    assertTrue("Chapters property should be optional", p.isNullable());
    p = (Constrained) constraints.get("remarks");
    assertTrue("Remarks property should be optional", p.isNullable());
  }
  @SuppressWarnings("rawtypes")
  private void ensureConstraintsPresent(
      String[] classSource, int classIndexToTest, int constraintCount) throws Exception {
    // We need to do a real test here to make sure
    GroovyClassLoader gcl = new GroovyClassLoader();
    Class[] classes = new Class[classSource.length];
    for (int i = 0; i < classSource.length; i++) {
      classes[i] = gcl.parseClass(classSource[i]);
    }

    DefaultGrailsDomainClass domainClass = new DefaultGrailsDomainClass(classes[classIndexToTest]);

    Map constraints = domainClass.getConstrainedProperties();

    ConstrainedProperty p = (ConstrainedProperty) constraints.get("name");
    Collection cons = p.getAppliedConstraints();

    assertEquals(
        "Incorrect number of constraints extracted: " + constraints, constraintCount, cons.size());
  }