1

我正在编写一些代码,但我无法弄清楚我的错误是怎么回事。我希望这里有人可以给我一些答案。这是我的代码(相关部分):

public class AppData implements Callable<Integer> {
    private static AppData appData = new AppData();

    private AppData() {
        System.out.println("AppData-Constructor");
    }

    public static AppData getInstance() {
        return appData;
    }

    @Override
    public Integer call() throws Exception { // your business logic goes here...
        return 0;
    }

    private boolean _validate;

    public boolean validate() {
        return _validate;
    }

    @Option(names = { "--validate" }, description = "", defaultValue = "false", hidden = false, interactive = false, paramLabel = "", required = false, type = boolean.class)
    public void set_validate(boolean validate) {
        System.out.println("Set Validate: " + validate);
        this._validate = validate;

        if(validate)
        {
            System.out.println("\nBeginne Programmvalidierung\n");
            Path tmp = null;
            try {
                // Doing some validation stuff
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

如您所见,我的班级是单身人士。注释来自 picoli,我用它来解析命令行参数。-callsSystem.out用于调试。这是我无法解释的行为:

当我使用例如“-h”作为参数启动我的应用程序时,我得到的帮助打印得很好。显示System.out.println单例已创建并set_validate()使用默认值调用。但是当我--validate用作论据时,情况就会改变。

由于某种原因,构造函数和默认集被连续调用两次。之后,set_validate() 被调用true(因为它应该)。但是,似乎第一次调用设置了静态实例变量,而最后一次调用 true 是在第二个实例上完成的(我的理论)。结果,当我从我的主方法(在另一个类中)检查我的单例实例的状态时,我得到了错误,因为它没有在正确的实例中设置_validatevalidate()

我使用搜索引擎检查:

  1. 除了静态单例实例(正如预期的那样,因为它是私有的)之外,不会在任何地方调用构造函数。
  2. _validate除了我发布的代码外,其他地方都无法访问。
  3. set_validate()不在任何地方调用。只有 Picocli 调用它。

我不知道接下来要检查什么。有任何想法吗?

问候

托尔斯滕

编辑: AppData是持有数据的多个类之一。它们都被收集在 Picocli 的一个大类中,如下所示:

class Data
{
    @AddGroup(...)
    AppData appData = AppData.getInstance();

    @AddGroup(...)
    FooData fooData = FooData.getInstance();

    @AddGroup(...)
    BarData barData = BarData.getInstance();
}

在我的主要方法中是这样使用的:

Data data = new Data();
CommandLine cmd = new CommandLine(data);
cmd.parseArgs(args);
4

1 回答 1

1

我怀疑(但只能猜测,因为未显示该部分代码)这AppData是另一个命令的子命令,或者应用程序使用 picocli 像这样:

int exitCode = new CommandLine(AppData.class).execute(args);

在这两种情况下,picocli 都会创建一个AppData使用反射的实例。picocli 创建的实例是从命令行值填充的实例。这是与返回的实例不同的实例AppData::getInstance

确保只有一个实例的一种方法是将单例实例传递给 picocli。例如:

AppData singleton = AppData.getInstance();
int exitCode = new CommandLine(singleton).execute(args);

System.out.println("validate=" + singleton.validate());

(如果AppData是子命令,还有其他方法可以访问 picocli 创建的实例,例如注入 picocli 模型的@Spec注释CommandSpec::userObject(),并在其上调用 getter 以获取AppData实例。)

现在,另一个问题是:为什么该set_validate方法会被调用两次?

从 4.2 版本开始,picocli 将首先@Option使用默认值调用 -annotated 方法,然后再解析命令行参数。因此,set_validate首先使用默认值调用该方法,然后使用命令行中指定的值再次调用该方法。

(从 4.3 版本(即将发布)开始,只有在命令行中没有指定值时才会设置set_validate默认值,因此从 4.3 版本开始,该方法只会被调用一次。)

于 2020-05-09T02:12:36.780 回答