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 }