@@ -28,6 +28,7 @@ import spock.lang.Unroll
2828import org.springframework.context.support.StaticMessageSource
2929
3030import grails.config.Settings
31+ import grails.util.Holders
3132import grails.databinding.BindUsing
3233import grails.databinding.BindingFormat
3334import grails.databinding.DataBindingSource
@@ -51,7 +52,7 @@ class GrailsWebDataBinderSpec extends Specification implements DataTest {
5152 mockDomains(
5253 AssociationBindingAuthor , AssociationBindingBook , AssociationBindingPage , Author , BinderNullabilityEntity ,
5354 Child , CollectionContainer , DataBindingBook , Fidget , Foo , GeneratedBindingChild , GeneratedBindingParent ,
54- Parent , Publication , Publisher , Team , Widget
55+ Parent , Publication , Publisher , RawCollectionContainer , Team , Widget
5556 )
5657 }
5758
@@ -1962,6 +1963,96 @@ class GrailsWebDataBinderSpec extends Specification implements DataTest {
19621963 obj. publishers. find { it. name == ' Pub One' }
19631964 obj. publishers. find { it. name == ' Pub Three' }
19641965 }
1966+
1967+ void ' test binding maps into a raw collection preserves the map elements' () {
1968+ given : ' a domain with a raw (non-generic) collection, whose component type falls back to Object'
1969+ def obj = new RawCollectionContainer ()
1970+
1971+ when : ' a list of maps is bound to it'
1972+ binder. bind(obj, new SimpleMapDataBindingSource ([
1973+ rawList : [[label : ' Answered' , param : ' status=resolved' ],
1974+ [label : ' Pending' , param : ' status=pending' ]]
1975+ ]))
1976+
1977+ then : ' the maps survive binding rather than being replaced by empty Object instances'
1978+ obj. rawList. size() == 2
1979+ obj. rawList. every { it instanceof Map }
1980+ obj. rawList[0 ]. label == ' Answered'
1981+ obj. rawList[0 ]. param == ' status=resolved'
1982+ obj. rawList[1 ]. label == ' Pending'
1983+ obj. rawList[1 ]. param == ' status=pending'
1984+ }
1985+
1986+ void ' test binding maps into a raw Set property preserves the map elements' () {
1987+ given :
1988+ def obj = new RawCollectionContainer ()
1989+
1990+ when :
1991+ binder. bind(obj, new SimpleMapDataBindingSource ([
1992+ rawSet : [[label : ' Answered' , param : ' status=resolved' ]]
1993+ ]))
1994+
1995+ then :
1996+ obj. rawSet. every { it instanceof Map }
1997+ obj. rawSet. first(). label == ' Answered'
1998+ }
1999+
2000+ void ' test binding maps into a raw Collection-typed property' () {
2001+ given :
2002+ def obj = new RawCollectionContainer ()
2003+
2004+ when :
2005+ binder. bind(obj, new SimpleMapDataBindingSource ([rawCollection : [[label : ' Answered' ]]]))
2006+
2007+ then :
2008+ obj. rawCollection. every { it instanceof Map }
2009+ obj. rawCollection[0 ]. label == ' Answered'
2010+ }
2011+
2012+ void ' test binding DataBindingSource items into a raw collection' () {
2013+ given :
2014+ def obj = new RawCollectionContainer ()
2015+
2016+ when :
2017+ binder. bind(obj, new SimpleMapDataBindingSource ([
2018+ rawList : [new SimpleMapDataBindingSource ([label : ' Answered' ])]
2019+ ]))
2020+
2021+ then :
2022+ obj. rawList. size() == 1
2023+ obj. rawList[0 ]. getClass() != Object
2024+ }
2025+
2026+ void ' test binding maps into a raw collection with deny-by-default enabled' () {
2027+ given : ' the opt-in hardening turned on, and the property explicitly allowlisted'
2028+ def originalConfig = Holders . config
2029+ Holders . setConfig(new PropertySourcesConfig ([(Settings . DATABINDING_DENY_BY_DEFAULT ): true ]))
2030+ DataBindingUtils . clearBindingCaches()
2031+ def obj = new RawCollectionContainer ()
2032+
2033+ when :
2034+ binder. bind(obj, new SimpleMapDataBindingSource ([
2035+ rawList : [[label : ' Answered' , param : ' status=resolved' ]]
2036+ ]), null , [' rawList' ], null , null )
2037+
2038+ then : ' the elements are still maps, as they are with the hardening off'
2039+ obj. rawList. size() == 1
2040+ obj. rawList[0 ] instanceof Map
2041+ obj. rawList[0 ]. label == ' Answered'
2042+
2043+ cleanup :
2044+ Holders . setConfig(originalConfig)
2045+ DataBindingUtils . clearBindingCaches()
2046+ }
2047+ }
2048+
2049+ @Entity
2050+ class RawCollectionContainer {
2051+
2052+ List rawList = []
2053+ Map rawMap = [:]
2054+ Set rawSet = []
2055+ Collection rawCollection = []
19652056}
19662057
19672058@Entity
0 commit comments