picocli не работает с jline3 в cmd.exe - PullRequest
0 голосов
/ 07 февраля 2019

Я хочу использовать picocli с jline3.Поэтому я создаю проект со следующим pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.flaxel</groupId>
<artifactId>picocli_test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>picocli</name>
<url>http://maven.apache.org</url>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>

    <picocli.version>3.9.3</picocli.version>
    <jline.version>3.9.0</jline.version>
</properties>

<dependencies>
    <dependency>
        <groupId>info.picocli</groupId>
        <artifactId>picocli</artifactId>
        <version>${picocli.version}</version>
    </dependency>
    <dependency>
        <groupId>info.picocli</groupId>
        <artifactId>picocli-shell-jline3</artifactId>
        <version>${picocli.version}</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.0.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.flaxel.picocli.App</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compile-plugin</artifactId>
            <version>3.7.0</version>
        </plugin>
    </plugins>
</build>

Теперь я скопировал класс со страницы picocli github :

package com.flaxel.picocli;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.MaskingCallback;
import org.jline.reader.ParsedLine;
import org.jline.reader.UserInterruptException;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.LineReaderImpl;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;

import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
import picocli.shell.jline3.PicocliJLineCompleter;

/**
 * Example that demonstrates how to build an interactive shell with JLine3 and
 * picocli.
 * 
 * @since 3.9
 */
public class App {

    /**
     * Top-level command that just prints help.
     */
    @Command(name = "", description = "Example interactive shell with completion", footer = { "",
        "Press Ctl-D to exit." }, subcommands = { MyCommand.class, ClearScreen.class })
    static class CliCommands implements Runnable {
        LineReaderImpl reader;
        PrintWriter out;

        CliCommands() {
        }

        public void setReader(LineReader reader) {
            this.reader = (LineReaderImpl) reader;
            out = reader.getTerminal().writer();
        }

        @Override
        public void run() {
            out.println(new CommandLine(this).getUsageMessage());
        }
    }

    /**
     * A command with some options to demonstrate completion.
     */
    @Command(name = "cmd", mixinStandardHelpOptions = true, version = "1.0", description = "Command with some options to demonstrate TAB-completion"
            + " (note that enum values also get completed)")
    static class MyCommand implements Runnable {
        @Option(names = { "-v", "--verbose" })
        private boolean[] verbosity = {};

        @Option(names = { "-d", "--duration" })
        private int amount;

        @Option(names = { "-u", "--timeUnit" })
        private TimeUnit unit;

        @ParentCommand
        CliCommands parent;

        @Override
        public void run() {
            if (verbosity.length > 0) {
                parent.out.printf("Hi there. You asked for %d %s.%n", amount, unit);
            } else {
                parent.out.println("hi!");
            }
        }
    }

    /**
     * Command that clears the screen.
     */
    @Command(name = "cls", aliases = "clear", mixinStandardHelpOptions = true, description = "Clears the screen", version = "1.0")
    static class ClearScreen implements Callable<Void> {

        @ParentCommand
        CliCommands parent;

        @Override
        public Void call() throws IOException {
            parent.reader.clearScreen();
            return null;
        }
    }

    public static void main(String[] args) {
        try {
            // set up the completion
            CliCommands commands = new CliCommands();
            CommandLine cmd = new CommandLine(commands);
            Terminal terminal = TerminalBuilder.builder().build();
            LineReader reader = LineReaderBuilder.builder()
                    .terminal(terminal)
                    .completer(new PicocliJLineCompleter(cmd.getCommandSpec()))
                    .parser(new DefaultParser())
                    .build();
            commands.setReader(reader);
            String prompt = "prompt> ";
            String rightPrompt = null;

            // start the shell and process input until the user quits with Ctrl-D
            String line;
            while (true) {
                try {
                    line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
                    ParsedLine pl = reader.getParser().parse(line, 0);
                    String[] arguments = pl.words().toArray(new String[0]);
                    CommandLine.run(commands, arguments);
                } catch (UserInterruptException e) {
                    // Ignore
                } catch (EndOfFileException e) {
                    return;
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

Если я запускаю код в Eclipse IDE, я могу написать команду в консоли и получить ответ.Но если я создаю файл JAR с Maven, он не работает.Я получаю следующую ошибку:

Ошибка: невозможно инициализировать основной класс com.flaxel.picocli.App. Причина: java.lang.NoClassDefFoundError: org / jline / reader / UserInterruptException

Я работаю с Eclipse 2018-09 и Java 11.

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

NoClassDefFoundError происходит, потому что вы пропускаете классы JLine при запуске вашего jar.Попробуйте использовать плагин Shade Maven, чтобы создать Uber-jar, содержащий все зависимости.

С JLine 3 в Windows вы, вероятно, захотите добавить зависимость org.jline:jline-terminal-jansi:3.9.0 в дополнение к info.picoli:picocli-shell-jline3:3.9.3.Без этого (или зависимости jline-terminal-jna) вы получите «тупой» терминал без цветов ANSI или автозаполнения.

(info.picoli:picocli-shell-jline3:3.9.3 введет info.picocli:picocli и org.jline:jline в качестве транзитивных зависимостей, поэтому нет необходимости включать их явно.)

0 голосов
/ 07 февраля 2019

Идеально, что работает для меня.Я использую плагин maven shade и добавляю некоторые свойства, поэтому я получаю pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.flaxel</groupId>
    <artifactId>picocli_test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>picocli</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>

        <picocli.version>3.9.3</picocli.version>
        <jline.version>3.9.0</jline.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>info.picocli</groupId>
            <artifactId>picocli</artifactId>
            <version>${picocli.version}</version>
        </dependency>
        <dependency>
            <groupId>info.picocli</groupId>
            <artifactId>picocli-shell-jline3</artifactId>
            <version>${picocli.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.flaxel.picocli.App</mainClass>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compile-plugin</artifactId>
                <version>3.7.0</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <createDependencyReducedPom>false</createDependencyReducedPom>
                            <shadedArtifactAttached>true</shadedArtifactAttached>
                            <shadedClassifierName>jar-with-dependencies</shadedClassifierName>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

EDIT

У меня есть хотя бы один вопрос.Если я запускаю приложение и хочу использовать завершение вкладки, оно не работает.Таким образом, я не получаю завершения, только четыре пробела установлены:

Фев.07, 2019 6:50:29 NACHM.org.jline.utils.Log logr ПРЕДУПРЕЖДЕНИЕ. Невозможно создать системный терминал, создать немой терминал (для получения дополнительной информации включите ведение журнала отладки)

prompt> cmd

Или ячто-то не так?

...