Applying Groovy extensions in Grails produces MissingMethodException for String#toBoolean()

馋奶兔 提交于 2019-12-05 00:33:11

问题


Background

Groovy have the feature of adding methods to the existing classes, and I've found some interesting ones.

Then I discovered that I need to customize my Grails bootstrap to load them, so I add:

def init = { servletContext -> addExtensionModules() }

  def addExtensionModules() {

    Map<CachedClass, List<MetaMethod>> map = [:]
    ClassLoader classLoader = Thread.currentThread().contextClassLoader
    try {
      Enumeration<URL> resources = classLoader.getResources(MetaClassRegistryImpl.MODULE_META_INF_FILE)
      for (URL url in resources) {
        if (url.path.contains('groovy-all')) {
          // already registered
          continue
        }
        Properties properties = new Properties()
        InputStream inStream
        try {
          inStream = url.openStream()
          properties.load(inStream)
          GroovySystem.metaClassRegistry.registerExtensionModuleFromProperties(properties,
                            classLoader, map)
        }
        catch (IOException e) {
          throw new GroovyRuntimeException("Unable to load module META-INF descriptor", e)
        } finally {
          inStream?.close()
        }
      }
    }  catch (IOException ignored) {}
    map.each { CachedClass cls, List<MetaMethod> methods ->
    cls.setNewMopMethods(methods)
  }
}

And I add in my BuildConfig.groovy

compile ('ca.redtoad:groovy-crypto-extensions:0.2') {
  excludes 'groovy-all'
}

The Question

The problem is that now I cannot use the toBoolean() method of Groovy String:

groovy.lang.MissingMethodException: No signature of method: java.lang.String.toBoolean() is applicable for argument types: () values: [] Possible solutions: asBoolean(), asBoolean(), toFloat(), toDouble()

Since groovy is already registered, why the method is missing? I'm using Grails 2.2.4.

EDIT

Tested in a groovy 2.0.8 console, and the code works, so probably is something related to Grails.

@Grab('ca.redtoad:groovy-crypto-extensions:0.2')
@GrabExclude('org.codehaus.groovy:groovy-all')

addExtensionModules() //same method of BootStrap, ommited to make shorter.

def key = "password".toKey()
def ciphertext = "some plaintext".bytes.encrypt(key: key)
def x = new String(ciphertext.decrypt(key: key)).toBoolean()
println "S".toBoolean()

回答1:


Replace

map.each { CachedClass cls, List<MetaMethod> methods ->
    cls.setNewMopMethods(methods)
}

with

map.each { CachedClass cls, List<MetaMethod> methods ->
    //Add new MOP methods instead of set them as new
    cls.addNewMopMethods(methods) 
}

When new meta method is set in the CachedClass the existing extensions/meta methods are overriden by the only provided extension from the extension module. In this case, groovy-crypto-extension uses the below extension methods on String class

class java.lang.String=
[public static javax.crypto.spec.SecretKeySpec ca.redtoad.groovy.extensions.crypto.CryptoExtensionMethods.toKey(java.lang.String), 
 public static javax.crypto.spec.SecretKeySpec ca.redtoad.groovy.extensions.crypto.CryptoExtensionMethods.toKey(java.lang.String,java.util.Map)
] 

If those methods are set to the CachedClass, the existing methods are wiped out. So it has to be replace with adding them to the CachedClass. Hence, making toBoolean available on String class.

Challenge accepted and executed. You owe me a treat. (Gift Card is acceptable too). ;)



来源:https://stackoverflow.com/questions/19564902/applying-groovy-extensions-in-grails-produces-missingmethodexception-for-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!