Skip to content

Commit

Permalink
[#451] Enhancement: Selectively disable reflective type converter reg…
Browse files Browse the repository at this point in the history
…istration.

Closes #451
  • Loading branch information
remkop committed Sep 27, 2018
1 parent 3ddbd15 commit 56dcfb8
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 6 deletions.
7 changes: 7 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ The picocli community is pleased to announce picocli 3.6.1.

This release contains bugfixes, minor enhancements and documentation improvements.

ANSI is automatically enabled on Windows if Jansi's `AnsiConsole` has been installed.

It is now possible to selectively avoid loading type converters with reflection.

Bugfix: Enum values were not rendered in `${COMPLETION-CANDIDATES}` for collection type options.

Many thanks to the many members of the picocli community who contributed!

This is the fortieth public release.
Expand All @@ -22,6 +28,7 @@ Picocli follows [semantic versioning](http://semver.org/).
- [#487] Enhancement: Auto-completion script should return from `generateOptionsSwitch` immediately if there is nothing to generate. Thanks to [David Walluck](https://github.com/dwalluck) for the pull request.
- [#483][#486] Enhancement: Improve `Help.Ansi.AUTO`: automatically enable ANSI on Windows if Jansi's `AnsiConsole` has been installed. Thanks to [Philippe Charles](https://github.com/charphi) for the pull request.
- [#491] Enhancement: Improve `Help.Ansi.AUTO` cygwin/msys detection on Windows.
- [#451] Enhancement: Selectively disable reflective type converter registration. Thanks to [Paolo Di Tommaso](https://github.com/pditommaso) for the suggestion.
- [#488] Doc: Clarify in user manual that `CommandLine.setPosixClusteredShortOptionsAllowed(false)` means that option parameters cannot be attached to the option name. Thanks to [Maryam Ziyad](https://github.com/MaryamZi) for raising this.
- [#492][#493] Doc: Add section on `@Command(aliases)` attribute to user manual. Thanks to [marinier](https://github.com/marinier) for the pull request.
- [#494] Bugfix: Enum values were not rendered in `${COMPLETION-CANDIDATES}` for collection type options.
Expand Down
18 changes: 12 additions & 6 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -381,32 +381,38 @@ the text value is converted to the type of the annotated field.
=== Built-in Types
Out of the box, picocli can convert command line argument strings to a number of common data types.

Most of the built-in types work with Java 5, but picocli also has some default converters for Java 7 types like `Path` and Java 8 types like `Duration`, etc. These converters are only available when running on a Java version that supports them. See the below list for details.
Most of the built-in types work with Java 5, but picocli also has some default converters for Java 7 types like `Path` and Java 8 types like `Duration`, etc. These converters are loaded using reflection and are only available when running on a Java version that supports them. See the below list for details.

* any Java primitive type or their wrapper
* any `enum`
* `String`, `StringBuilder`, `CharSequence`
* `java.math.BigDecimal`, `java.math.BigInteger`
* `java.nio.Charset`
* `java.io.File`
* `java.nio.file.Path` (from picocli 2.2, requires Java 7 or higher)
* `java.net.InetAddress`
* `java.util.regex.Pattern`
* `java.util.Date` (for values in `"yyyy-MM-dd"` format)
* `java.sql.Time` (for values in any of the `"HH:mm"`, `"HH:mm:ss"`, `"HH:mm:ss.SSS"`, or `"HH:mm:ss,SSS"` formats)
* `java.sql.Timestamp` (from picocli 2.2, for values in the `"yyyy-MM-dd HH:mm:ss"` or `"yyyy-MM-dd HH:mm:ss.fffffffff"` formats)
* `java.net.URL`, `java.net.URI`
* `java.util.UUID`
* `java.time` value objects: `Duration`, `Instant`, `LocalDate`, `LocalDateTime`, `LocalTime`, `MonthDay`, `OffsetDateTime`, `OffsetTime`, `Period`, `Year`, `YearMonth`, `ZonedDateTime`, `ZoneId`, `ZoneOffset` (from picocli 2.2, requires Java 8 or higher, invokes the `parse` method of these classes)
* `java.lang.Class` (from picocli 2.2, for the fully qualified class name)
* `java.nio.ByteOrder` (from picocli 2.2, for the Strings `"BIG_ENDIAN"` or `"LITTLE_ENDIAN"`)
* `java.util.Currency` (from picocli 2.2, for the ISO 4217 code of the currency)
* `java.net.NetworkInterface` (from picocli 2.2, for the InetAddress or name of the network interface)
* `java.util.TimeZoneConverter` (from picocli 2.2, for the ID for a TimeZone)

Converters loaded using reflection:

* `java.nio.file.Path` (from picocli 2.2, requires Java 7 or higher)
* `java.time` value objects: `Duration`, `Instant`, `LocalDate`, `LocalDateTime`, `LocalTime`, `MonthDay`, `OffsetDateTime`, `OffsetTime`, `Period`, `Year`, `YearMonth`, `ZonedDateTime`, `ZoneId`, `ZoneOffset` (from picocli 2.2, requires Java 8 or higher, invokes the `parse` method of these classes)
* `java.sql.Time` (for values in any of the `"HH:mm"`, `"HH:mm:ss"`, `"HH:mm:ss.SSS"`, or `"HH:mm:ss,SSS"` formats)
* `java.sql.Timestamp` (from picocli 2.2, for values in the `"yyyy-MM-dd HH:mm:ss"` or `"yyyy-MM-dd HH:mm:ss.fffffffff"` formats)
* `java.sql.Connection` (from picocli 2.2, for a database url of the form `jdbc:subprotocol:subname`)
* `java.sql.Driver` (from picocli 2.2, for a database URL of the form `jdbc:subprotocol:subname`)


TIP: Sometimes loading converters with reflection is not desirable.
Use system property `picocli.converters.excludes` to specify a comma-separated list of fully qualified class names for which the converter should not be loaded.
Regular expressions are supported.
For example, invoking the program with `-Dpicocli.converters.excludes=java.sql.Ti.*` will not load type converters for `java.sql.Time` and `java.sql.Timestamp`.

=== Custom Type Converters
Register a custom type converter to handle data types other than the above built-in ones.
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/picocli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -7516,6 +7516,7 @@ private Object createTime(long epochMillis) {
}

public static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer) {
if (excluded(FQCN, tracer)) { return; }
try {
registry.put(Class.forName(FQCN), new ISO8601TimeConverter());
} catch (Exception e) {
Expand Down Expand Up @@ -7578,6 +7579,7 @@ static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Trace
registerIfAvailable(registry, tracer, fqcn, fqcn, factoryMethodName, paramTypes);
}
static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer, String fqcn, String factoryClass, String factoryMethodName, Class<?>... paramTypes) {
if (excluded(fqcn, tracer)) { return; }
try {
Class<?> cls = Class.forName(fqcn);
Class<?> factory = Class.forName(factoryClass);
Expand All @@ -7590,6 +7592,16 @@ static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Trace
traced.add(fqcn);
}
}
static boolean excluded(String fqcn, Tracer tracer) {
String[] excludes = System.getProperty("picocli.converters.excludes", "").split(",");
for (String regex : excludes) {
if (fqcn.matches(regex)) {
tracer.debug("BuiltIn type converter for %s is not loaded: (picocli.converters.excludes=%s)%n", fqcn, System.getProperty("picocli.converters.excludes"));
return true;
}
}
return false;
}
static Set<String> traced = new HashSet<String>();
static class ReflectionConverter implements ITypeConverter<Object> {
private final Method method;
Expand Down
52 changes: 52 additions & 0 deletions src/test/java/picocli/CommandLineTypeConversionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -818,4 +818,56 @@ class CustomConverter {