1 /** 2 * Copyright (C) 2016 Gary Gregory. All rights reserved. 3 * 4 * See the NOTICE.txt file distributed with this work for additional 5 * information regarding copyright ownership. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 package com.garygregory.jcommander.converters; 20 21 import java.net.URI; 22 import java.util.Objects; 23 24 import com.beust.jcommander.ParameterException; 25 import com.beust.jcommander.converters.BaseConverter; 26 import com.beust.jcommander.converters.IntegerConverter; 27 import com.garygregory.jcommander.converters.net.URIConverter; 28 29 /** 30 * Provides common services for converters in this package 31 * 32 * @param <T> 33 * the target type of the conversion. 34 * @since 1.0.0 35 * @author <a href="mailto:ggregory@garygregory.com">Gary Gregory</a> 36 */ 37 public abstract class AbstractBaseConverter<T> extends BaseConverter<T> { 38 39 /** 40 * The target class to convert strings. 41 */ 42 protected final Class<T> targetClass; 43 44 /** 45 * Whether or not a null conversion failure throws a ParameterException. 46 */ 47 protected final boolean failOnNull; 48 49 /** 50 * Constructs a new instance for the given option and target class. 51 * 52 * @param optionName 53 * The option name, may be null. 54 * @param targetClass 55 * must not be null 56 */ 57 public AbstractBaseConverter(final String optionName, final Class<T> targetClass) { 58 this(optionName, targetClass, true); 59 } 60 61 /** 62 * Constructs a new instance for the given option, target class and fail-on-null. 63 * 64 * @param optionName 65 * may be null 66 * @param targetClass 67 * must not be null 68 * @param failOnNull 69 * if true, the converter fails when the conversion results in a null value 70 */ 71 public AbstractBaseConverter(final String optionName, final Class<T> targetClass, final boolean failOnNull) { 72 super(optionName); 73 this.failOnNull = failOnNull; 74 this.targetClass = Objects.requireNonNull(targetClass, "targetClass for " + getClass()); 75 } 76 77 /** 78 * Converts the given value or throws a {@link ParameterException}. Delegates the actual conversion to subclasses with 79 * {@link #convertImpl(String)}. 80 * 81 * @param value 82 * the value to convert. 83 * @throws ParameterException 84 * for a conversion problem 85 */ 86 @Override 87 public T convert(final String value) { 88 try { 89 final T result = convertImpl(value); 90 if (result == null && failOnNull) { 91 throw newParameterException(value); 92 } 93 return result; 94 } catch (final Exception e) { 95 throw newParameterException(value, e); 96 } 97 } 98 99 /** 100 * Converts a value. 101 * 102 * @param value 103 * the value to convert 104 * @return the converted value 105 * @throws Exception 106 * subclasses can throw any Exception 107 */ 108 protected abstract T convertImpl(String value) throws Exception; 109 110 /** 111 * Builds an error message for the given value in error 112 * 113 * @param value 114 * the value that cause the error 115 * @return an error message 116 */ 117 protected String getErrorString(final String value) { 118 return getClass().getName() + " could not convert \"" + value + "\" to an instance of " + targetClass + " for option " 119 + getOptionName(); 120 } 121 122 /** 123 * Returns true if the array is of size 1, false otherwise. 124 * 125 * @param split 126 * an array 127 * @return true if the array is of size 1, false otherwise. 128 */ 129 protected boolean isSingle(final String[] split) { 130 return split.length == 1; 131 } 132 133 /** 134 * Creates a new {@link ParameterException} for the given value. 135 * 136 * @param value 137 * the value in error 138 * @return a new ParameterException 139 */ 140 protected ParameterException newParameterException(final String value) { 141 return new ParameterException(getErrorString(value)); 142 } 143 144 /** 145 * Creates a new {@link ParameterException} for the given value and throwable 146 * 147 * @param value 148 * the value in error 149 * @param t 150 * the throwable 151 * @return a new ParameterException 152 */ 153 protected ParameterException newParameterException(final String value, final Throwable t) { 154 return new ParameterException(getErrorString(value), t); 155 } 156 157 /** 158 * Splits the given string using {@link ConverterConstants#VALUE_SEPARATOR} as the boundary. 159 * 160 * @param value 161 * the string to split 162 * @return the split array result 163 */ 164 protected String[] split(final String value) { 165 return value.split(ConverterConstants.VALUE_SEPARATOR); 166 } 167 168 /** 169 * Converts the given value to an int for the given option. 170 * 171 * @param optionName 172 * the option name 173 * @param value 174 * the value to parse 175 * @return the int result 176 */ 177 protected int toInt(final String optionName, final String value) { 178 return new IntegerConverter(optionName).convert(value).intValue(); 179 } 180 181 /** 182 * Converts the given string into a URI 183 * 184 * @param optionName 185 * the option name 186 * @param value 187 * a string 188 * 189 * @return a new URI 190 * @see java.net.URI 191 */ 192 protected URI toURI(final String optionName, final String value) { 193 return new URIConverter(null).convert(value); 194 } 195 196 }