Reputation: 187389
The CountryTagLib
provided by Grails has an (out-of-date) list of Countries
class CountryTagLib {
static final ISO3166_3 = [
"scg":"Serbia and Montenegro",
"zmb":"Zambia"
]
}
I want to update this Map to replace the "Serbia and Montenegro" entry with an entry for each of Serbia and Montenegro.
I can't simply update the contents of the Map or use metaprogramming because the contents of ISO3166_3
are copied into other variables in a static initializer
static {
ISO3166_3.each { k, v ->
COUNTRY_CODES_BY_NAME[v] = k
}
}
I need the code that modifies ISO3166_3
to be executed before this static initializer runs. I don't think there's any way I can achieve this, so I'm left with only the unpalatable option of copy-pasting the whole CountryTagLib
into a custom taglib and modifying ISO3166_3
therein. I'll also have to change every <g:countrySelect>
to use my tag instead. I really don't want to do this....
Upvotes: 1
Views: 1269
Reputation: 171164
Yan's method is the cleanest IMO, but for future reference; one way to chain back to the replaced method in a metaClass override is to store the old method somewhere, then invoke this in the new method:
class CountryTagLib {
static final ISO3166_3 = [
"scg":"Serbia and Montenegro",
"zmb":"Zambia"
]
}
// Get a handle to our old static getISO3166_3 method
def originalGetter = CountryTagLib.metaClass.getStaticMetaMethod( 'getISO3166_3', [] as Object[] )
CountryTagLib.metaClass.static.getISO3166_3 = {
// Call the old method, and manipulate the map it returns
originalGetter.invoke( delegate, null ).with {
remove('scg')
put( 'srb', 'Serbia' )
put( 'mon', 'Montenegro' )
it
}
}
Upvotes: 2
Reputation: 2982
Why are you not accessing the map directly? The field is final
which means you cannot modify the field itself but not its content:
You cannot do:
CountryTagLib.ISO3166_3 = xxxx // this will fail (final)
but this should work:
CountryTagLib.ISO3166_3.remove('scg')
..etc...
Upvotes: 2