I'm getting a NullPointerException when accessing static constraints - grails

The code
${personRequest.constraints.requestStatus.inList}
in my gsp file throws a NullPointerException, but new PersonRequest().constraints.. works. Why? Isn't constraints static?

Copied from here (grails-user mailing list)
but why accesing to static fields
doesnt work?
Because the "constraints" static field
is a closure property. It has no
sub-properties relating to the
constraints.
Grails evaluates this closure using a
constraint builder which monitors
"calls" to methods that don't exist,
i.e. the property names you use:
type( inList: [xxxxx])
...causes a method call to "type" with
a Map parameter containing "inList"
==> some value.
From this info, Grails builds up a
list of all the constraints
available and binds them to future
instances of the domain class.
So, when you access User.constraints
statically, you are getting a
Closure.
We -could- look at replacing the value
of the static constraints property
at runtime after evaluating the
Closure it is initialized with.
However this could be a bit "too much"
magic. What do people think?
FYI it's like this now because until
0.4 (if I recall) constraints weren't static, and in 0.4 they can
still be non-static. Only in 0.5
will we throw an exception/ignore
non-static constraints.

Related

Is there a modifiable Iterable type?

I need a modifiable collection like a List or a Set to be passed as a parameter. Using Iterable doesn't guarantee this argument to have methods like add or remove.
Example method:
void foo(Iterable bar) {
bar.add(); // The method 'add' isn't defined for the type 'Iterable'.
}
Is there a class / interface for (modifiable) collections which guarantees those methods? If not, why?
There is not a modifiable type. Very early (before Dart 1) we had some other types in our hierarchy, but we decided to avoid including them because things were getting a bit too complex.
I still wish we'd shipped a List interface without the mutation members. 🤷

Grails 3 Accessing Grails domain constraints at runtime

I used to access grails 2 constraints in my gsp like this :
${MyDomainClass.constraints.myProperty.inList.collect{it.name()}}
It doesn't work in Grails 3 anymore
In Grails 3.0 domain and command objects are using the trait grails.validation.Validateable (Source can be found here). That trait gives you access to the constraints by providing the following method.
static Map<String, ConstrainedProperty> getConstraintsMap();
In order to access the constraints you call that method on your domain or command object. The following example accesses the nullable constraint on a domain objects property called day.
domainObject.getConstraintsMap()['day']['nullable']
That way, which was valid in Grails 2, still works...
grailsApplication.getArtefact('Domain',
'MyDomainClass').getConstrainedProperties().myProperty.inList.collect{it.name()}
see GrailsDomainClass API

Can one constraint on a command object check the result of another?

This is a simple example that doesn't work, I'm wondering if there is a way to validate a inside the validator block of b if it hasn't already been validated.
Example how I thought it would work:
static constraints =
{
a nullable: false
b validator: { val, obj ->
if(obj.errors.hasFieldError('a'))
{
return false
}
}
}
Note: in this scenario obj.errors.hasFieldError('a') returns false even if a is null.
I don't think there's any guarantee of the order the constraints are checked, and it's unlikely that it would have anything to do with the order specified in the constraints block.
However, in addition to the common one-arg custom validator that passes you the current value for that field and the two-arg validator you show where you also get access to the domain class instance, there's a three-arg variant (unfortunately it doesn't seem to be covered in the Grails reference docs ...) where the third argument is the Spring Errors instance. If you define a three-arg validator, GORM ignores any return value since it's assumed that you'll be working directly with the Errors instance, calling one or more of the different rejectValue methods yourself for any validation issues.
So you could remove from the constraints block any standard validations that you want to run yourself and use this approach instead. You can find more information about working with the Errors object in the Spring docs.

Is there a list of forbidden method names for Grails domain objects?

Often as I add a helper method to a domain object I get an error when compiling which resolves to "x property is not found". This seems to happen for methods name getX, setX, and also recently isX. Is there a list of name forms that I should avoid? Is there a way to annotate or otherwise label these methods so Grails doesn't confuse them with auto properties?
Grails autodetects properties and assumes that they're persistent. Public fields in Groovy create a getter and setter under the hood so getters are assumed to be associated with persistent fields.
But if you want a helper method that starts with 'get' or 'is' but isn't a getter for a persistent field, you have two options. One is to use the transients list - see http://grails.org/doc/latest/ref/Domain%20Classes/transients.html
The other option is to declare the return value as def. Since it's not typed (def is an alias for Object) Hibernate can't persist it since it doesn't know what data type to use, so it's ignored.
My preference is the transients list because I would rather have self-documenting methods where it's obvious what they do, what parameter types they accept, and what they return.
I have no idea of common list - it's too diverse. Convention methods are added by different parts of Groovy and Grails:
Groovy convention about property getters/setters is very basic thing. It's impossible have a getX() method and not have read access to x property.
Grails domain class dynamic methods and Domain class convention properties are specific to Grails domain classes;
Same for controllers, and so on;
Groovy convention about property getters/setters, including methodMissing, propertyMissing, $staticMethodMissing, getProperty, properties and so on;
Groovy adds a number of as<Type>() methods, like asInteger();
different plugins could inject more convention methods.
To access declared field, not getter/setter, use java field access operator.
As far as I understand your problem, you can use transient !
static transients = ['feildName']

Distinguishing between Grails domain-class fields and getBlah() methods via GrailsDomainClassProperty

I'm writing a Groovy script (as part of a Grails plugin) and I want to get a list of properties for a GrailsDomainClass that a user of my plugin might define. I can do this using domainClass.properties (where domainClass is a GrailsDomainClass).
However, suppose a user has the grails domain class:
class Example {
String name
static constraints = {
}
def getSomeNonExistingProperty(){
return "Not-a-real-property"
}
}
In this case, domainClass.properties returns a list with both name and someNoneExistingProperty
I understand that this is because of Grails is generating a read-only property on-the-fly for use where someone has a getBlah() method. That's great, but in my script I want to perform some actions with the "real" properties only (or at least non read-only properties).
That is, I would like some way of distinguishing or identifying someNonExistingProperty as a read-only property, or, alternatively, as a property generated by Grails and not entered explicitly as a field in the domainClass by the user of my plugin.
I've looked at the GrailsDomainClassProperty Class and it has a range of methods providing information about the property. However, none of them appear to tell me whether a property is read-only or not, or to allow me to distinguish between a field defined in the domainClass and a field created on-the-fly by Grails as a result of a "getSomeNonExistingProperty()" method.
Am I missing something obvious here? Is there a way of getting a list of just the explicitly user-defined fields (eg name, in the above example)?
I believe transient properties are what you are trying to exclude
I've run into this problem a few times, and instead of trying to work around it I typically just end up renaming my getX() method. It's probably the easiest option.
Edit:
Alternatively, I wonder if you could use reflection to see which methods are defined on the class, and while iterating over your properties see if the property has an explicit getter defined, and omit it. I'm not very familiar with reflection when it comes to Groovy and Grails, especially with the dynamic methods, but it's a possible route of investigation.

Resources