Dónal
Dónal

Reputation: 187389

replace static field

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.

Update

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

Answers (2)

tim_yates
tim_yates

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

yan
yan

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

Related Questions