Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grails databinding - How to exclude child property

How can I exclude the child domain property when I use the grailsWebDataBinder?

For example, I have domains:

class Car {
   String carPropertyToExclude

   Set<Detail> details

   static hasMany = [details: Detail]
}

class Detail {
   String detailPropertyToExclude

   static belongsTo= [car: Car]
}

I want to exclude the detailPropertyToExclude from Detail when I call the bind method of grailsWebDataBinder and give the car instance as a parameter

Code:

List blackList = ["carPropertyToExclude"]
grailsWebDataBinder.bind(car, new SimpleMapDataBindingSource(params), null, blackList)

Note: Don't suggest the bindable: false or variants when excluded from anywhere. Only need to know is there a way to do it by providing blackList as bind() method parameter.

These variants also not working:

List blackList = ["carPropertyToExclude", "details.detailPropertyToExclude"]
List blackList = ["carPropertyToExclude", [Detail.class : "detailPropertyToExclude"]]

The main question is how to prepare the blackList to exclude also child's property?

like image 508
Beno Arakelyan Avatar asked Jan 25 '26 12:01

Beno Arakelyan


1 Answers

blacklist parameter supports only direct object properties

you can use DataBindingListener

import grails.databinding.events.DataBindingListenerAdapter

class BlackListener extends DataBindingListenerAdapter{
    List<String> list
    //returns false if you want to exclude property from binding
    public Boolean beforeBinding(Object obj, String propertyName, Object value, Object errors) {
        return !list.contains("${obj?.class.name}.${propertyName}".toString())
    }
}

...

List blackList = ["Car.carPropertyToExclude", "Details.detailPropertyToExclude"]
grailsWebDataBinder.bind(car, new SimpleMapDataBindingSource(params), 
                new BlackListener(list:blackList) )

UPD:

Unfortunately the method above does not work with Collection binding.

The problem that SimpleDataBinder.setPropertyValue(...) method loses listener when processing a list.

Not sure if following workaround is good (potentially context initialization required)

but it's possible to register converter for each black list:

import grails.databinding.SimpleDataBinder
import grails.databinding.SimpleMapDataBindingSource
import grails.databinding.converters.ValueConverter

SimpleDataBinder setBlackList(SimpleDataBinder binder, Map<Class,List<String>> blackLists) {
    blackLists.each { Class clazz, List<String> blackList ->
        def vc = new ValueConverter(){
            boolean canConvert(Object value){
                return value instanceof Map
            }
            Object convert(Object value){
                def obj = clazz.newInstance()
                binder.bind( obj, new SimpleMapDataBindingSource(value), [], blackList )
                return obj
            }
            Class<?> getTargetType(){ clazz }
        }
        binder.registerConverter(vc)
    }
    return binder
}

...

Map blackLists = [
    (Car.class)    : ["carPropertyToExclude"],
    (Detail.class) : ["detailPropertyToExclude"]
]

setBlackList(grailsWebDataBinder,blackLists)

...

grailsWebDataBinder.bind(car, new SimpleMapDataBindingSource(params), null, 
         blackLists[car.getClass()] )

PS: as alternative possible to set grailsWebDataBinder.conversionService...

like image 195
daggett Avatar answered Jan 27 '26 14:01

daggett



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!