I have a grails domain class with an embedded object, I want to validate the embedded object's attributes only while updating.
I know I can do this on a normal grails domain class by using a custom validator and checking if the domain's class id is not null.
I can't do this because of the lack of an id on an embedded object.
There is a little example of what I want to do.
//This is on domain/somePackage/A.groovy
class A{
B embeddedObject
static embedded = ['embeddedObject']
static constraints = {
embeddedObject.attribute validator:{val, obj-> //The app fails to start when this code is added!!
if(obj.id && !val) //if the id is not null it means the object it's updating...
return 'some.error.code'
}
}
}
//this class is on src/groovy/somePackage/B.groovy
class B{
String attribute
static constraints={
attribute validator:{val,obj->
if(obj.id && !val) //This will fail too! because the lack of an id on this object....
return 'some.error.code'
}
}
}
Is there a way to get the id of the 'parent' on the embedded object??
Any help will be appreciated
way too complicated:
class A{
B embeddedObject
static embedded = ['embeddedObject']
static constraints = {
embeddedObject validator:{ val, obj ->
if( obj.id && !val.attribute )
return 'some.error.code'
}
}
}
Related
I'm having a problem where the related table id fields return 'null' from my domain objects when using inheritance. Here is an example:
In /src/groovy/
BaseClass1.groovy
class BaseClass1 {
Long id
static mapping = {
tablePerConcreteClass true
}
}
BaseClass2.groovy
class BaseClass2 extends BaseClass1 {
String someOtherProperty
static constraints = {
someOtherProperty(maxSize:200)
}
static mapping = BaseClass1.mapping
}
In /grails-app/domain
ParentClass.groovy
class ParentClass extends BaseClass2 {
ChildClass myChild
static mapping = BaseClass2.mapping << {
version false
}
}
ChildClass.groovy
class ChildClass extends BaseClass1 {
String property
static mapping = BaseClass1.mapping
}
The problem appears here:
SomeotherCode.groovy
print parentClassInstance.myChild.id // returns the value
print parentClassInstance.myChildId // returns null
Any ideas what might be going on to get those dynamic properties to break like this?
After debugging into the get(AssociationName)Id source, I found the following:
The handler for this is:
GrailsDomainConfigurationUtil.getAssociationIdentifier(Object target, String propertyName,
GrailsDomainClass referencedDomainClass) {
String getterName = GrailsClassUtils.getGetterName(propertyName);
try {
Method m = target.getClass().getMethod(getterName, EMPTY_CLASS_ARRAY);
Object value = m.invoke(target);
if (value != null && referencedDomainClass != null) {
String identifierGetter = GrailsClassUtils.getGetterName(referencedDomainClass.getIdentifier().getName());
m = value.getClass().getDeclaredMethod(identifierGetter, EMPTY_CLASS_ARRAY);
return (Serializable)m.invoke(value);
}
}
catch (NoSuchMethodException e) {
// ignore
}
catch (IllegalAccessException e) {
// ignore
}
catch (InvocationTargetException e) {
// ignore
}
return null;
}
It threw an exception on the related class (value.getClass().getDeclaredMethod), saying NoSuchMethod for the method getId(). I was unable to remove the id declaration from the base class without Grails complaining that an identifier column was required. I tried marking id as public and it also complained that it wasn't there. So, I tried this
BaseClass {
Long id
public Long getId() { return this.#id }
}
and things worked on some classes, but not on others.
When I removed the ID declaration, I go an error: "Identity property not found, but required in domain class". On a whim, I tried adding #Entity to the concrete classes and viola! everything started working.
class BaseClass {
//Don't declare id!
}
#Entity
class ParentClass {}
#Entity
class ChildClass {}
I still think it is a grails bug that it needs to be added, but at least it is easy enough to work around.
I'm not sure why you are seeing this behavior, but I'm also not sure why you are doing some of the things you are doing here. Why have a domain class extend a POGO? Domains, Controllers, and Services are heavily managed by the Grails machinery, which probably was not designed for this sort of use. Specifically, I believe Grails builds the dynamic property getters for the GrailsDomainProperty(s) of GrailsDomainClass(es), not POGO's. In this case, you have an explicitly declared id field in BaseClass1 that is not a GrailsDomainProperty. I suspect that this POGO id property is not picked up by the Grails machinery that creates the dynamic property getters for Domains.
You might try putting BaseClass1/2 in /grails-app/domain, perhaps making them abstract if you don't want them instantiated, then extending them as you are and seeing if you observe the behavior you want.
Class A
{
static constraints = {
bObj(nullable:true)
}
B bObj
static hasMany = [listB:B]
}
Class B
{
static constraints = {
aObj(nullable:true)
}
A aObj
}
Problem that Im facing is, when I retrive instance of A(whereas bObj.aObj is null) & call save on it, automatically adds reference of A into bObj.aObj, which was null before calling save().
Any thoughts on why would it happen.
I have 2 domain classes
class a {
String name
static constraints = {
name unique:true
}
}
class b {
String description
}
and in domain class b I want to call class a
import a
class b {
String description
static constraints = {
description unique:'a.name'
}
}
and get error
Scope for constraint [unique] of property [description] of class [b] must be a valid property name of same class
How do I get a property from class a to b?
Assuming you try to do this in Grails 2+
You can't use validation that way. In your example you need to reference to a property of the same domain class. To correct the constraint in class B you can write:
class B {
String description
static contraints = {
description unique:true
}
}
But I think you want to import the constraints from class a which is done like this.
class B {
String description
static contraints = {
importFrom A
}
}
See http://grails.org/doc/latest/guide/validation.html#sharingConstraints
This will import all constraints on properties that the two classes share. Which in your case is none.
UPDATE
I got a similar question and found a solution for it. So I thought to share it here with you.
The problem can be solved with a custom validator. In your case constraints for class B:
static constraints = {
description(validator: {
if (!it) {
// validates to TRUE if the collection is empty
// prevents NULL exception
return true
}
def names = A.findAll()*.name
return names == names.unique()
})
}
It's difficult to answer your question correctly since the requirements are a bit odd. But maybe it will help.
You need to write a custom validator to check the uniqueness since it relies on more information than the single instance of b will have.
Something like
static constraints {
description validator: { val ->
!a.findByName(val)
}
}
might do the trick.
I'm having trouble getting saves cascaded down my object hierarchy. Below is the code of my object hierarchy.
class Entity {
static hasMany = [attributes: Attribute]
}
class Attribute extends ValuePossessor {
static belongsTo = Entity
}
abstract class ValuePossessor {
def valueService
Value value
void setValue(val) {
this.value = valueService.Create(val)
this.value.possessor = this
}
}
abstract class Value {
static belongsTo = [possessor: ValuePossessor]
}
class StringValue extends Value {
String value
}
The valueService is simply a service with a big switch statement that creates the correct value type (string, boolean, int, etc.).
Entity e = new Entity()
Attribute attr = new Attribute()
attr.setValue(1)
e.addToAttributes(attr)
e.save()
The above code correctly creates all objects, but fails to save the value object. The entity and attribute are saved, but the value is not. Am I missing some identifier needed to cascade all the way down to the value object?
Figured this out. Apparently there is some magic in the grails dynamic setters. I changed the setValue(val) method to set(val) and it started working. Lesson learned: don't override grails' dynamically added methods because they are built with magic, pixy dust, and unicorn urine.
I have a property that can be nullable or required depending on the status of another variable.
class Person{
name()
civilStatus(inList:['Single','Married','Divorced','Widowed'])
partnerOrSpouse()
}
the partnerOrSpouse property is nullable or not depending on the value of the civilStatus property.
You can use a custom validator. Using the two-parameter version, the first is the value being validated and the second is the domain class instance. You can refer to other properties via the 'obj' parameter:
class Person {
...
static constraints = {
name()
civilStatus inList:['Single','Married','Divorced','Widowed']
partnerOrSpouse validator: { val, obj ->
if (obj.civilStatus == 'Single') {
return 'some.error.code'
}
}
}
}