/*
 * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.graalvm.options;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;

Represents a type of an option that allows to convert string values to Java values.
Since:19.0
/** * Represents a type of an option that allows to convert string values to Java values. * * @since 19.0 */
public final class OptionType<T> { private static final Consumer<?> EMPTY_VALIDATOR = new Consumer<Object>() { public void accept(Object t) { } }; private final String name; private final Converter<T> converter; private final Consumer<T> validator; private final boolean isOptionMap;
Constructs a new option type with name and function that allows to convert a string to the option type and validator of the option values.
Params:
  • name – the name of the type.
  • stringConverter – a function that converts a string value to the option value. Can throw IllegalArgumentException to indicate an invalid string.
  • validator – used for validating the option value. Throws IllegalArgumentException if the value is invalid.
Since:19.0
/** * Constructs a new option type with name and function that allows to convert a string to the * option type and validator of the option values. * * @param name the name of the type. * @param stringConverter a function that converts a string value to the option value. Can throw * {@link IllegalArgumentException} to indicate an invalid string. * @param validator used for validating the option value. Throws * {@link IllegalArgumentException} if the value is invalid. * * @since 19.0 */
public OptionType(String name, Function<String, T> stringConverter, Consumer<T> validator) { this(name, new Converter<T>() { @Override public T convert(T previousValue, String key, String value) { return stringConverter.apply(value); } }, validator, false); } private OptionType(String name, Converter<T> converter, Consumer<T> validator, boolean isOptionMap) { Objects.requireNonNull(name); Objects.requireNonNull(converter); Objects.requireNonNull(validator); this.name = name; this.converter = converter; this.validator = validator; this.isOptionMap = isOptionMap; }
Constructs a new option type with name and function that allows to convert a string to the option type.
Params:
  • name – the name of the type.
  • stringConverter – a function that converts a string value to the option value. Can throw IllegalArgumentException to indicate an invalid string.
Since:19.0
/** * Constructs a new option type with name and function that allows to convert a string to the * option type. * * @param name the name of the type. * @param stringConverter a function that converts a string value to the option value. Can throw * {@link IllegalArgumentException} to indicate an invalid string. * * @since 19.0 */
@SuppressWarnings("unchecked") public OptionType(String name, Function<String, T> stringConverter) { this(name, stringConverter, (Consumer<T>) EMPTY_VALIDATOR); }
Deprecated:Use OptionType(String, Function, Consumer)
Since:19.0
/** * @deprecated Use {@link #OptionType(String, Function, Consumer)} * @since 19.0 */
@Deprecated @SuppressWarnings("unused") public OptionType(String name, T defaultValue, Function<String, T> stringConverter, Consumer<T> validator) { this(name, stringConverter, validator); }
Deprecated:Use OptionType(String, Function)
Since:19.0
/** * @deprecated Use {@link #OptionType(String, Function)} * @since 19.0 */
@Deprecated @SuppressWarnings("unused") public OptionType(String name, T defaultValue, Function<String, T> stringConverter) { this(name, stringConverter); }
Deprecated:
Since:19.0
/** * @deprecated * @since 19.0 */
@Deprecated public T getDefaultValue() { return null; }
Returns the name of this type.
Since:19.0
/** * Returns the name of this type. * * @since 19.0 */
public String getName() { return name; }
Converts a string value, validates it, and converts it to an object of this type.
Throws:
  • IllegalArgumentException – if the value is invalid or cannot be converted.
Since:19.0
/** * Converts a string value, validates it, and converts it to an object of this type. * * @throws IllegalArgumentException if the value is invalid or cannot be converted. * @since 19.0 */
public T convert(String value) { T v = converter.convert(null, null, value); validate(v); return v; }
Converts a string value, validates it, and converts it to an object of this type. For option maps includes the previous map stored for the option and the key.
Params:
  • nameSuffix – the key for prefix options.
  • previousValue – the previous value holded by option.
Throws:
Since:19.2
/** * Converts a string value, validates it, and converts it to an object of this type. For option * maps includes the previous map stored for the option and the key. * * @param nameSuffix the key for prefix options. * @param previousValue the previous value holded by option. * @throws IllegalArgumentException if the value is invalid or cannot be converted. * @since 19.2 */
@SuppressWarnings("unchecked") public T convert(Object previousValue, String nameSuffix, String value) { T v = converter.convert((T) previousValue, nameSuffix, value); validate(v); return v; }
Validates an option value and throws an IllegalArgumentException if the value is invalid.
Throws:
Since:19.0
/** * Validates an option value and throws an {@link IllegalArgumentException} if the value is * invalid. * * @throws IllegalArgumentException if the value is invalid or cannot be converted. * @since 19.0 */
public void validate(T value) { validator.accept(value); }
Since:19.0
/** * @since 19.0 */
@Override public String toString() { return "OptionType[name=" + name + "]"; } private static final Map<Class<?>, OptionType<?>> DEFAULTTYPES = new HashMap<>(); static { DEFAULTTYPES.put(Boolean.class, new OptionType<>("Boolean", new Function<String, Boolean>() { public Boolean apply(String t) { if ("true".equals(t)) { return Boolean.TRUE; } else if ("false".equals(t)) { return Boolean.FALSE; } else { throw new IllegalArgumentException(String.format("Invalid boolean option value '%s'. The value of the option must be '%s' or '%s'.", t, "true", "false")); } } })); DEFAULTTYPES.put(Byte.class, new OptionType<>("Byte", new Function<String, Byte>() { public Byte apply(String t) { try { return Byte.parseByte(t); } catch (NumberFormatException e) { throw new IllegalArgumentException(e.getMessage(), e); } } })); DEFAULTTYPES.put(Integer.class, new OptionType<>("Integer", new Function<String, Integer>() { public Integer apply(String t) { try { return Integer.parseInt(t); } catch (NumberFormatException e) { throw new IllegalArgumentException(e.getMessage(), e); } } })); DEFAULTTYPES.put(Long.class, new OptionType<>("Long", new Function<String, Long>() { public Long apply(String t) { try { return Long.parseLong(t); } catch (NumberFormatException e) { throw new IllegalArgumentException(e.getMessage(), e); } } })); DEFAULTTYPES.put(Float.class, new OptionType<>("Float", new Function<String, Float>() { public Float apply(String t) { try { return Float.parseFloat(t); } catch (NumberFormatException e) { throw new IllegalArgumentException(e.getMessage(), e); } } })); DEFAULTTYPES.put(Double.class, new OptionType<>("Double", new Function<String, Double>() { public Double apply(String t) { try { return Double.parseDouble(t); } catch (NumberFormatException e) { throw new IllegalArgumentException(e.getMessage(), e); } } })); DEFAULTTYPES.put(String.class, new OptionType<>("String", new Function<String, String>() { public String apply(String t) { return t; } })); }
Returns the default option type for a given value. Returns null if no default option type is available for the Java type of this value.
Since:19.0
/** * Returns the default option type for a given value. Returns <code>null</code> if no default * option type is available for the Java type of this value. * * @since 19.0 */
@SuppressWarnings("unchecked") public static <T> OptionType<T> defaultType(T value) { return defaultType((Class<T>) value.getClass()); }
Returns the default option type for option maps for the given value class. Returns null if no default option type is available for the value class.
/** * Returns the default option type for option maps for the given value class. Returns * <code>null</code> if no default option type is available for the value class. */
@SuppressWarnings("unchecked") static <V> OptionType<OptionMap<V>> mapOf(Class<V> valueClass) { final OptionType<V> valueType = defaultType(valueClass); if (valueType == null) { return null; } return new OptionType<>("OptionMap", new Converter<OptionMap<V>>() { @Override public OptionMap<V> convert(OptionMap<V> previousValue, String key, String value) { OptionMap<V> map = previousValue; if (map == null || map.entrySet().isEmpty()) { map = new OptionMap<>(new HashMap<>()); } map.backingMap.put(key, valueType.convert(map.get(key), key, value)); return map; } }, (Consumer<OptionMap<V>>) EMPTY_VALIDATOR, true); }
Returns the default option type for a class. Returns null if no default option type is available for this Java type.
Since:19.0
/** * Returns the default option type for a class. Returns <code>null</code> if no default option * type is available for this Java type. * * @since 19.0 */
@SuppressWarnings("unchecked") public static <T> OptionType<T> defaultType(Class<T> clazz) { OptionType<T> type = (OptionType<T>) DEFAULTTYPES.get(clazz); if (type != null) { return type; } if (Enum.class.isAssignableFrom(clazz)) { return defaultEnumType(clazz); } return null; } @SuppressWarnings("unchecked") private static <T> OptionType<T> defaultEnumType(Class<T> clazz) { return new OptionType<>(clazz.getSimpleName(), new Function<String, T>() { @SuppressWarnings("rawtypes") public T apply(String t) { Class<? extends Enum> enumType = (Class<? extends Enum>) clazz; try { if (t != null) { return (T) Enum.valueOf(enumType, t); } // fallthrough to failed } catch (IllegalArgumentException e) { // fallthrough to failed } StringBuilder b = new StringBuilder(); String sep = ""; for (Enum constant : enumType.getEnumConstants()) { b.append(sep); b.append('\''); b.append(constant.name()); b.append('\''); sep = ", "; } throw new IllegalArgumentException("Invalid option value '" + t + "'. Valid options values are: " + b.toString()); } }); } boolean isOptionMap() { return isOptionMap; } @FunctionalInterface private interface Converter<T> { T convert(T previousValue, String key, String value); } }