Written on
GContracts 1.1.3 Released!
I am proud to announce that GContracts 1.1.3 has just been released and is available now in the Central Maven repository [0] and at Github [1]. The release includes bug fixes and advanced support Spring bean classes annotated with GContracts' annotations.Concrete AssertionError
types
In parallel with @Invariant
, @Requires
and @Ensures
GContracts 1.1.3 provides separate exception types which all are descendants of AssertionError
and I guess do not need further explanation:
ClassInvariantViolation
, PreconditionViolation
and PostconditionViolation
.
Advanced Support for Spring Beans
One of the problems with GContracts is its lack of compatibility especially with Grails artifact classes, i.e. controllers, services, domain classes etc. This topic has been brought to me a few times and if you just want to apply let's say class invariants on Spring bean classes the Spring application container's initialization lifecycle can quickly become your enemy. Let's consider the following service:
@Invariant({ anotherService != null })
class MyService {
def anotherService
static transactional = true
// ...
}
MyService
is a simple Grails service class, annotated with a class invariant which ensures that the reference to anotherService
will never be null
, during the entire life-time of the MyService
bean. Sadly enough, whenever the Spring application container tries to create a new instance of a MyService
bean it fails because GContracts checks the class invariant directly after the object's constructor has completed successfully. By that time, the Spring application container is not yet done with object construction.
From a theoretical perspective throwing a ClassInvariantViolation
in this place is completely reasonable since an object's class invariant needs to be fulfilled by the object instance during its entire life-time. But from a practical perspective, this is kind of pain. It means that you have to duplicate the class invariant to all methods in the service class, e.g.
// avoid invariant checks during construction
class MyService {
def anotherService
static transactional = true
@Requires({ anotherService != null })
def myServiceMethod() {
// ...
}
@Requires({ anotherService != null })
def yetAnotherServiceMethod() {
// ...
}
}
@PostConstruct
method which overtakes the class invariant check. Since GContracts has no mechanism to know that the given class is a Spring-managed class at runtime, programmers need to annotate their artifact classes with appropriate stereotype annotations [2], e.g. a service class with @Service
, a controller with @Controller
, etc.
@Service
@Invariant({ anotherService != null })
class MyService {
def anotherService
static transactional = true
// ...
}
@Service
stereotype annotation above triggers GContracts' "Spring compliance mode". Whenever the service bean above has been constructed by the Spring application container it will automatically check the class invariant.
The programmer clearly needs to make a compromise in this case, because the class invariant won't be checked after a construction call anymore (e.g. in a test-case where the programmer simply creates an instance of this service class). But this is a consequence of outsourcing object creation to the application container.
Hint: GContracts supports the -ea
/-da
VM parameters [3] which you can use to deactivate assertion checking during application execution, whereas activating assertion checking only during test-cases.
Changes
ISSUE-25: better support for Spring component classes with class invariants ISSUE-24: wrong class invariant placement with inherited invariant ISSUE-23: @Requires on constructor with super statement causes compilation error ISSUE-22: Separate Exception Types for Pre-, Postconditions and Class Invariant ISSUE-17: remove direct reference to PowerAssertionError