【问题标题】:Groovy command using inheritance cannot compile in Spring Boot remote shell使用继承的 Groovy 命令无法在 Spring Boot 远程 shell 中编译
【发布时间】:2017-03-19 23:39:33
【问题描述】:

我有一个抽象的 groovy 类,其中包含一些我想从其他 groovy 命令类扩展的实用方法(用于 Spring Boot 的远程 shell)。然而,当我尝试运行 groovy 命令类时,我得到了一个CommandException

我的 groovy 抽象类如下所示。

package commands 
import com.xyz.MyService
import org.crsh.command.InvocationContext
import org.springframework.beans.factory.BeanFactory

abstract class abstractcmd {
    private static final String SPRING_FACTORY = "spring.beanfactory"

    protected MyService getMyService(InvocationContext context) {
        return getBeanFactory(context).getBean(MyService.class);
    }

    private BeanFactory getBeanFactory(InvocationContext context) {
        return context.attributes[SPRING_FACTORY];
    }
}

我的 groovy 命令类如下所示。

package commands
import org.crsh.cli.Command
import org.crsh.cli.Usage
import org.crsh.command.InvocationContext

@Usage("do something commands")
class foo extends abstractcmd {
    @Command
    @Usage("bar")
    def String bar(InvocationContext context) {
        try {
            getMyService(context).bar()
            return "did bar"
        } catch (Exception e) {
            return String.format("could not do bar: %s", e.toString())
        }
    }
}

当我通过 SSH 进入 shell 并执行 foo bar 时,出现以下异常。

org.crsh.shell.impl.command.spi.CommandException:无法创建命令 foo 实例 在 org.crsh.lang.impl.groovy.GroovyCompiler$1.getCommand(GroovyCompiler.java:192) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.lang.LanguageCommandResolver.resolveCommand(LanguageCommandResolver.java:101) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.command.CRaSH.getCommand(CRaSH.java:100) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.command.CRaSHSession.getCommand(CRaSHSession.java:96) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.lang.impl.script.PipeLineFactory.create(PipeLineFactory.java:89) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.lang.impl.script.ScriptRepl.eval(ScriptRepl.java:88) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.command.CRaSHSession.createProcess(CRaSHSession.java:163) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.async.AsyncProcess.execute(AsyncProcess.java:172) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.Console.iterate(Console.java:219) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.Console.on(Console.java:158) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.Console.on(Console.java:135) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.jline.JLineProcessor.run(JLineProcessor.java:204) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.ssh.term.CRaSHCommand.run(CRaSHCommand.java:99) ~[crash.connectors.ssh-1.3.2.jar:?] 在 java.lang.Thread.run(Thread.java:745) [?:1.8.0_111]

如果我从 abstractcmdfoo 类中删除 package commands 行,那么 IDE (IntelliJ) 和 shell 都会抱怨找不到 abstractcmd

2017-03-19 19:34:06 错误 org.crsh.shell.impl.command.CRaSHProcess.execute:84 - 评估请求“foo”时出错,无法编译命令脚本 foo org.crsh.shell.impl.command.spi.CommandException:无法编译命令脚本 foo 在 org.crsh.lang.impl.groovy.GroovyClassFactory.parse(GroovyClassFactory.java:65) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.lang.impl.groovy.GroovyCompiler$1.getCommand(GroovyCompiler.java:172) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.lang.LanguageCommandResolver.resolveCommand(LanguageCommandResolver.java:101) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.command.CRaSH.getCommand(CRaSH.java:100) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.command.CRaSHSession.getCommand(CRaSHSession.java:96) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.lang.impl.script.PipeLineFactory.create(PipeLineFactory.java:89) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.lang.impl.script.ScriptRepl.eval(ScriptRepl.java:88) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.command.CRaSHSession.createProcess(CRaSHSession.java:163) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.shell.impl.async.AsyncProcess.execute(AsyncProcess.java:172) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.Console.iterate(Console.java:219) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.Console.on(Console.java:158) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.Console.on(Console.java:135) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.console.jline.JLineProcessor.run(JLineProcessor.java:204) ~[crash.shell-1.3.2.jar:?] 在 org.crsh.ssh.term.CRaSHCommand.run(CRaSHCommand.java:99) ~[crash.connectors.ssh-1.3.2.jar:?] 在 java.lang.Thread.run(Thread.java:745) [?:1.8.0_111] 引起:org.codehaus.groovy.control.MultipleCompilationErrorsException:启动失败: foo: 9: 无法解析类 abstractcmd @ 第 9 行,第 1 列。 @Usage("条") ^ 1 个错误 在 org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310) ~[groovy-2.4.7.jar:2.4.7] 在 org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:946) ~[groovy-2.4.7.jar:2.4.7] 在 org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593) ~[groovy-2.4.7.jar:2.4.7] 在 org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:542) ~[groovy-2.4.7.jar:2.4.7] 在 groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298) ~[groovy-2.4.7.jar:2.4.7] 在 groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268) ~[groovy-2.4.7.jar:2.4.7] 在 org.crsh.lang.impl.groovy.GroovyClassFactory.parse(GroovyClassFactory.java:59) ~[crash.shell-1.3.2.jar:?] ... 14 更多

如果我不扩展abstractcmd(从而在命令类中实现“util”方法)并删除package 行,我能够使自定义命令正常工作的唯一方法。

我正在使用 Spring Boot v1.5.1.RELEASE。

关于我做错了什么有什么想法吗?

【问题讨论】:

    标签: java spring spring-boot groovy crash-shell


    【解决方案1】:

    看起来 CRaSH 在扩展其他 groovy 类的 groovy 类方面存在问题,因为如果您不扩展一个,它就可以正常工作。

    很抱歉,我没有时间充分调查如何以及为什么(更正/更新非常受欢迎),并且在 docs 中没有找到任何内容,但好消息是您可以扩展抽象java类来实现同样的事情。我偶然发现了这样的a sample for the cron command,它使用以下javadoc扩展了GroovyCommand抽象类:

    /**
     * The base command for Groovy class based commands.
     */
    public abstract class GroovyCommand extends BaseCommand implements GroovyObject
    

    因此,长话短说,您可以使用以下解决方法:

    抽象SpringAwareCommandjava类

    package crash.commands;
    
    import org.crsh.command.BaseCommand;
    import org.springframework.beans.factory.BeanFactory;
    
    public abstract class SpringAwareCommand extends BaseCommand {
    
        private static final String SPRING_BEAN_FACTORY = "spring.beanfactory";
    
        protected <T> T getBean(Class<T> beanClass) {
            return ((BeanFactory) this.context.getAttributes().get(SPRING_BEAN_FACTORY)).getBean(beanClass);
        }
    
    }
    

    更新了foo groovy 类

    package crash.commands
    
    import com.xyz.MyService
    import org.crsh.cli.Command
    import org.crsh.cli.Usage
    
    @Usage("do something commands")
    class foo extends SpringAwareCommand {
        @Command
        @Usage("bar")
        def String bar() {
            try {
                getBean(MyService.class).bar()
                return "did bar"
            } catch (Exception e) {
                return String.format("could not do bar: %s", e.toString())
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-11-29
      • 1970-01-01
      • 2014-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-01
      相关资源
      最近更新 更多