diff --git a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java index bcf8d071604c..08b01439834e 100644 --- a/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java +++ b/spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,13 @@ * without spaces by an equals sign ("="). The value may optionally be * an empty string. * + *
This parser supports the POSIX "end of options" delimiter, meaning that + * any {@code "--"} (empty option name) in the command signals that all remaining + * arguments will non-optional. For example, here {@code "--opt=ignored"} is considered + * as a non-optional argument. + *
+ * --foo=bar -- --opt=ignored+ * *
* --foo @@ -53,6 +60,7 @@ * * @author Chris Beams * @author Sam Brannen + * @author Brian Clozel * @since 3.1 */ class SimpleCommandLineArgsParser { @@ -65,23 +73,26 @@ class SimpleCommandLineArgsParser { */ public CommandLineArgs parse(String... args) { CommandLineArgs commandLineArgs = new CommandLineArgs(); + boolean endOfOptions = false; for (String arg : args) { - if (arg.startsWith("--")) { + if (!endOfOptions && arg.startsWith("--")) { String optionText = arg.substring(2); - String optionName; - String optionValue = null; int indexOfEqualsSign = optionText.indexOf('='); if (indexOfEqualsSign > -1) { - optionName = optionText.substring(0, indexOfEqualsSign); - optionValue = optionText.substring(indexOfEqualsSign + 1); + String optionName = optionText.substring(0, indexOfEqualsSign); + String optionValue = optionText.substring(indexOfEqualsSign + 1); + if (optionName.isEmpty()) { + throw new IllegalArgumentException("Invalid argument syntax: " + arg); + } + commandLineArgs.addOptionArg(optionName, optionValue); } - else { - optionName = optionText; + else if (!optionText.isEmpty()){ + commandLineArgs.addOptionArg(optionText, null); } - if (optionName.isEmpty()) { - throw new IllegalArgumentException("Invalid argument syntax: " + arg); + else { + // '--' End of options delimiter, all remaining args must be non-optional + endOfOptions = true; } - commandLineArgs.addOptionArg(optionName, optionValue); } else { commandLineArgs.addNonOptionArg(arg); diff --git a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java index 4e3f186f87b0..4331a4af91e2 100644 --- a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java +++ b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ * * @author Chris Beams * @author Sam Brannen + * @author Brian Clozel */ class SimpleCommandLineArgsParserTests { @@ -66,11 +67,6 @@ void withMixOfOptionsHavingValueAndOptionsHavingNoValue() { assertThat(args.getOptionValues("o3")).isNull(); } - @Test - void withEmptyOptionText() { - assertThatIllegalArgumentException().isThrownBy(() -> parser.parse("--")); - } - @Test void withEmptyOptionName() { assertThatIllegalArgumentException().isThrownBy(() -> parser.parse("--=v1")); @@ -112,4 +108,13 @@ void assertNonOptionArgsIsUnmodifiable() { args.getNonOptionArgs().add("foo")); } + @Test + void supportsEndOfOptionsDelimiter() { + CommandLineArgs args = parser.parse("--o1=v1", "--", "--o2=v2"); + assertThat(args.containsOption("o1")).isTrue(); + assertThat(args.containsOption("o2")).isFalse(); + assertThat(args.getOptionValues("o1")).containsExactly("v1"); + assertThat(args.getNonOptionArgs()).contains("--o2=v2"); + } + }