3
votes

Not sure how to frame this question, but I am seeing some behavior that I am unable to explain ... any help will be highly appreciated. I have a super-class Form, and sub-class DraftForm. The super-class has a more stringent constraint on a property content(blank: false) than the sub-class content(nullable: true), and I am using tablePerHierarchy false. The domain classes are as follows.

class Form {
    String content

    static constraints = { content(blank: false) }

    static mapping = { tablePerHierarchy false }
}
class DraftForm extends Form {

    static constraints = { content(nullable: true) }
}

With the above domain models, the following test * passes * without any problem.

class DraftFormIntegrationSpec extends Specification {

    void "Testing a draft-form and a form derived from a draft-form"(){

        given: "A draft-form with invalid form-fields"          // 1
        def draftForm = new DraftForm()

        when: "The draft-form is validated"                     // 2
        assert draftForm.validate() == true

        then: "The draft-form has no error"                     // 3
        !draftForm.hasErrors()

        when: "The draft-form is saved"                         // 4
        try{
            draftForm.save()
        }catch(Exception e){
            println "Exception thrown!"
            println e.class
        }

        then: "The draft-form is not found in the database"     // 5
        draftForm.id == null

        when: "The draft-form is casted to a form"              // 6
        Form form = (Form) draftForm
        assert form.validate() == true

        then: "The form validates, and has no error"            // 7
        !form.hasErrors()
    }
}

Here are my questions:

  • I think a sub-class also inherits the super-class's constraints. In that case, how come the draft form validates fine and has no error even though the content is null (please see // 2 and // 3 in the test)?
  • If the draft-form validates fine, why do I get an exception (// 4) and cannot find the draft-form in the database (// 5)?
  • When the DraftForm is type casted to a Form, it still validates fine and has no error (// 6 and // 7), even though the content property is still null. How is that possible?

    Thank you for the help!

  • 1
    save() return the instance or null so in your tests you need to use assert draftForm.save() != null or draftForm.save(failOnError:true).user800014
    Thanks @Sergio. If I did draftForm.save(failOnError: true) without the try-catch, the test does fail by throwing an exception when it tries to save. However, I am puzzled that the draftForm validates without any issue (// 2) and has no error (// 3), but still I cannot save it. Although, the fact that I cannot save explains draftForm.id == null (// 5), but still I cannot explain how it can validate without any error but still cannot save.tikka

    1 Answers

    0
    votes

    Please find answers below

    As per grails doc https://grails.github.io/grails-doc/3.0.x/guide/GORM.html > Inheritance Strategies

    tablePerHierarchy:false will have NOT-NULL constraint applied to content in form table at the database level, hence you got exception while saving the form object NULL not allowed for column "CONTENT".

    1. Yes subclass do inherits super-class constraints but for same property subclass constraints will be given priority for subclass object. Hence its validating in //2 and //3.
    2. exception is due to not-null column content in form table so NULL not allowed for column "CONTENT" as discussed before.
    3. When the DraftForm is type casted to a Form, its still an object of draftForm(try form.class and you will see "class draft.DraftForm") hence got validated, if you make a new object of Form it will fail the validation as content would be null.

    Hope this makes you understand things better.