Grails 3 Accessing Grails domain constraints at runtime - grails

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

Related

Grails 4 replacement for DefaultGrailsDomainClass?

I'm recreating a working Grails 2.2.5 application in Grails 4 in order to get to know the new version (with the view to migrating all 2.2.x apps over in due course). So far I've only moved a handful of Groovy classes from the src directory over, but I'm running into a compile problem with a class which is apparently no longer present in Grails 4, org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass. I use this to iterate through the persistent properties of a domain class (with persistentProperties). How would I do this in Grails 4? I.e., get all the persistent properties of a domain class?
DefaultGrailsDomainClass is indeed deprecated since Grails 3.3.2 in favor of the mapping context API. Fortunately, it is quite straightforward to replace the deprecated implementation.
Inject the grailsDomainClassMappingContext bean in your service or controller:
def grailsDomainClassMappingContext
then get the persistent entity by providing its name:
def entity = grailsDomainClassMappingContext.getPersistentEntity(domainObjName)
where domainObjName is a string and entity is an instance of org.grails.datastore.mapping.model.PersistentEntity. You can also get a specific property by using:
def property = entity.getPropertyByName(propertyName)
where propertyName is a string and property is an instance of org.grails.datastore.mapping.model.PersistentProperty.
The interfaces PersistentEntity and PersistentProperty offer a variety of useful methods to cover many uses.

Difference between two action signatures in grails

In grails we can define an action using 2 ways:-
def actionname()
{
}
and
def actionname = {
}
What is the difference between the two styles? When I tried to insert a spring security annotation above the action (second style) it said "#Secured" not applicable to field.
What does this mean? Is it because of closure?
The Grails reference docs 7.The Web Layer mentions the use of closures for controller actions in earlier versions of Grails, the preference is now to use methods. However, both are supported. It goes on to list some benefits of using methods instead.
Personally, I use methods in all my controllers and have also come across the issue with annotations such as #Secured that only work on methods and not the closures.
In earlier versions of Grails option 2 (actions as closures) was the only supported style. Grails 2.x introduced the actions-as-methods style and this is now the recommended approach, but the closure style is still supported for backwards compatibility and you'll see it if you are working on an app (or plugin) that was originally written on Grails 1.x.
The first is normal method definition with undefined return type.
The second is an assigment of a closure to a property 'actionname'.
That is why you get "#Secured" not applicable to field message, because this annotation is for methods only.
Shuttsy is correct that that the first way is now a preffered way to define actions in Grails.
This is an agreeable way of defining methods in Groovy at minimal level having the structure above.
The second way of defining is not refering to a method definition rather it's somehow a rule like closure constraints that governs a given class or method. Like when it is used in domain class .
Example
class Person {
String name
Person parent
static belongsTo = [ supervisor: Person ]
static mappedBy = [ supervisor: "none", parent: "none" ]
static constraints = { supervisor nullable: true }
//this allowed for methods only and why you got an error in above cases
#override
def toString(){
return name.toString()
}
}
#Secured annotation accept list of roles (String[])
it is used only for a method definition based on
toString() method inside the class ...i just give u a scenario of the two ..
#Secured annotation since spring security 2.0 supports method only. As a result, you have to convert closures to real methods if you want to apply the security annotation for it. Read more #Secured Annotation.

Grails warning at compile of controllers

I am currently getting the warning in Grails of
'The [update] action accepts a parameter of type [edu.acu.teachereval.SubjectCode] which has not been marked with #Validateable. Data binding will still be applied to this command object but the instance will not be validateable.
#Transactional'
along with the same errors for show, save, edit, and delete for the controller mentioned in the error and other controllers that I have created. I have seen this issue for user created functions, but I have not seen this error for functions that are built in to grails. Any assistance would be appreciated.
I think you need to add a #Validateable annotation to your SubjectCode class.
Reference
This may be coming late, But this error is likely to occur when you use models not created in the domain conventional folder.
It seems grails automatically injects the #Validateable annotation to domain classes/models in the domain Folder,
If you therefore create your models in the src/grails or src/java folder, You are likely to get this error when the model object is passed/posted/submited via a View to a controller function.
Try adding the #Validateable annotation to the domain object
Move the domain model to the domain grails convention folder
or maybe Grails is overreaching while simultaneously giving misleading error messages... nah, that never happens. For a more relevant answer, see:
Groovy / Grails using a map as a parameter of a function

Grails access Config properties in Secured annotation

I am trying to access the Config of the grails application via the #Secured annotation of spring security with the aim to externalize the role name later.
Sadly, I wasn't able to get this working. Neither by trying to use deprecated ConfigurationHolder class nor getting reference to grailsApplication object.
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
#Secured([CH.config.grails.app.user])
class MyController { ...}
Config.groovy:
...
grails.app.user = "ROLE_APPNAME_USER"
...
Does anyone have an advice how to solve this?
EDIT
Came across Burt's article which was informational.
You can't - annotation element values must be compile-time constants because they're resolved by the compiler and stored as part of the class bytecode.
You may have more luck using one of the other mechanisms to specify security constraints (static rules or Requestmap instances in the database) instead of annotations.

I'm getting a NullPointerException when accessing static constraints

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.

Resources