name:
src/main/java/io/protobase/f7/utils/Converters.java
-rw-r--r--
9615
1package io.protobase.f7.utils;
2
3import io.protobase.f7.errors.F7Exception;
4import io.protobase.f7.errors.ValueException;
5import io.protobase.f7.models.Grid;
6
7import java.text.DecimalFormat;
8import java.util.Objects;
9
10public class Converters {
11
12 /**
13 * Compare two objects using their type precedence first, and then defaulting to their default class compare methods
14 * if they are of the same type. If one is null, use a default depending on type.
15 *
16 * @param first - object to compare. Should be Double, Boolean, String, or null.
17 * @param second - second object to compare. Should be Double, Boolean, String, or null.
18 * @return ComparisonResult indicating less-than, greater-than, equal-to.
19 */
20 public static ComparisonResult compare(Object first, Object second) {
21 Integer firstTypePrecedence = Converters.getTypePrecedence(first);
22 Integer secondTypePrecedence = Converters.getTypePrecedence(second);
23 if (firstTypePrecedence.equals(secondTypePrecedence)) {
24 if (Objects.isNull(first)) {
25 return ComparisonResult.EQUAL;
26 }
27 if (first instanceof Double) {
28 Double firstAsDouble = Converters.castAsDouble(first);
29 Double secondAsDouble = Converters.castAsDouble(second);
30 return ComparisonResult.fromComparison(firstAsDouble.compareTo(secondAsDouble));
31 }
32 if (first instanceof Boolean) {
33 Boolean firstAsBoolean = Converters.castAsBoolean(first);
34 Boolean secondAsBoolean = Converters.castAsBoolean(second);
35 return ComparisonResult.fromComparison(firstAsBoolean.compareTo(secondAsBoolean));
36 }
37 if (first instanceof String) {
38 String firstAsString = Converters.castAsString(first).toLowerCase();
39 String secondAsString = Converters.castAsString(second).toLowerCase();
40 return ComparisonResult.fromComparison(firstAsString.compareTo(secondAsString));
41 }
42 }
43 if (Objects.isNull(first)) {
44 if (second instanceof Double) {
45 Double firstAsDouble = 0.0;
46 Double secondAsDouble = Converters.toPositiveZero(Converters.castAsDouble(second));
47 return ComparisonResult.fromComparison(firstAsDouble.compareTo(secondAsDouble));
48 }
49 if (second instanceof Boolean) {
50 Boolean firstAsBoolean = false;
51 Boolean secondAsBoolean = Converters.castAsBoolean(second);
52 return ComparisonResult.fromComparison(firstAsBoolean.compareTo(secondAsBoolean));
53 }
54 if (second instanceof String) {
55 String firstAsString = "";
56 String secondAsString = Converters.castAsString(second).toLowerCase();
57 return ComparisonResult.fromComparison(firstAsString.compareTo(secondAsString));
58 }
59 }
60 if (Objects.isNull(second)) {
61 if (first instanceof Double) {
62 Double firstAsDouble = Converters.toPositiveZero(Converters.castAsDouble(first));
63 Double secondAsDouble = 0.0;
64 return ComparisonResult.fromComparison(firstAsDouble.compareTo(secondAsDouble));
65 }
66 if (first instanceof Boolean) {
67 Boolean firstAsBoolean = Converters.castAsBoolean(first);
68 Boolean secondAsBoolean = false;
69 return ComparisonResult.fromComparison(firstAsBoolean.compareTo(secondAsBoolean));
70 }
71 if (first instanceof String) {
72 String firstAsString = Converters.castAsString(first).toLowerCase();
73 String secondAsString = "";
74 return ComparisonResult.fromComparison(firstAsString.compareTo(secondAsString));
75 }
76 }
77 return ComparisonResult.fromComparison(firstTypePrecedence.compareTo(secondTypePrecedence));
78 }
79
80 protected static Object textToZero(Object value) {
81 if (value instanceof Grid) {
82 Grid grid = Converters.castAsDataGrid(value);
83 if (grid.getColumnSize() == 1 && grid.getRowSize() == 1) {
84 return textToZero(grid.get(0, 0));
85 } else {
86 throw new ValueException("Grid value could not be found.");
87 }
88 }
89 if (value instanceof String) {
90 return 0.0;
91 }
92 return value;
93 }
94
95 /**
96 * Convert double to +0.0, only if it is -0.0.
97 *
98 * @param value to ensure is positive zero.
99 * @return value or +0.0 if value is -0.0.
100 */
101 public static Double toPositiveZero(double value) {
102 if (value == -0.0) {
103 return 0.0;
104 }
105 return value;
106 }
107
108 /**
109 * Convert a Double, String or Boolean to a Double. If F7Exception is the value, then throw it. For all other classes,
110 * a {@link ValueException} will be thrown. If the value is null, 0.0 is returned.
111 *
112 * @param value - to convert to Double.
113 * @return Double for sure, or exception.
114 */
115 public static Double toDouble(Object value) {
116 if (value instanceof Double) {
117 return Converters.toPositiveZero(Converters.castAsDouble(value));
118 }
119 if (value instanceof String) {
120 try {
121 return Double.parseDouble(Converters.castAsString(value));
122 } catch (NumberFormatException e) {
123 throw new ValueException("Cannot coerce to number");
124 }
125 }
126 if (value instanceof Boolean) {
127 return Converters.castAsBoolean(value) ? 1.0 : 0.0;
128 }
129 if (value instanceof F7Exception) {
130 throw Converters.castAsF7Error(value);
131 }
132 if (value instanceof Grid) {
133 Grid grid = Converters.castAsDataGrid(value);
134 if (grid.getColumnSize() == 1 && grid.getRowSize() == 1) {
135 return toDouble(grid.get(0, 0));
136 } else {
137 return 0.0;
138 }
139 }
140 if (Objects.isNull(value)) {
141 return 0.0;
142 }
143 throw new ValueException("Cannot coerce to number");
144 }
145
146 /**
147 * Convert a value to a string.
148 *
149 * @param value - to convert to text.
150 * @return String for sure.
151 */
152 public static String toText(Object value) {
153 if (value instanceof Boolean) {
154 return Converters.castAsBoolean(value) ? "TRUE" : "FALSE";
155 }
156 if (value instanceof String) {
157 return value.toString();
158 }
159 if (value instanceof Double) {
160 Double number = Converters.castAsDouble(value);
161 double remainder = number % 1;
162 if (Converters.toPositiveZero(remainder).equals(0.0)) {
163 DecimalFormat format = new DecimalFormat();
164 format.setMaximumFractionDigits(0);
165 format.setGroupingUsed(false);
166 return format.format(number);
167 }
168 return value.toString();
169 }
170 if (value instanceof F7Exception) {
171 return Converters.castAsF7Error(value).toString();
172 }
173 if (value instanceof Grid) {
174 Grid grid = Converters.castAsDataGrid(value);
175 if (grid.getColumnSize() == 1 && grid.getRowSize() == 1) {
176 return toText(grid.get(0, 0));
177 } else {
178 return "";
179 }
180 }
181 if (Objects.isNull(value)) {
182 return "";
183 }
184 throw new ValueException("Cannot coerce to text");
185 }
186
187 /**
188 * Convert a value to a boolean.
189 *
190 * @param value - to convert to a boolean.
191 * @return Boolean for sure, or throw ValueException.
192 */
193 public static Boolean toBoolean(Object value) {
194 if (value instanceof Boolean) {
195 return Converters.castAsBoolean(value);
196 }
197 if (value instanceof String) {
198 String rawStringValue = ((String) value);
199 if (rawStringValue.toLowerCase().equals("true")) {
200 return true;
201 }
202 if (rawStringValue.toLowerCase().equals("false")) {
203 return false;
204 }
205 if (rawStringValue.equals("")) {
206 return false;
207 }
208 throw new ValueException("Cannot coerce to boolean");
209 }
210 if (value instanceof F7Exception) {
211 throw Converters.castAsF7Error(value);
212 }
213 if (value instanceof Grid) {
214 Grid grid = Converters.castAsDataGrid(value);
215 if (grid.getColumnSize() == 1 && grid.getRowSize() == 1) {
216 return toBoolean(grid.get(0, 0));
217 } else {
218 return false;
219 }
220 }
221 if (value instanceof Double) {
222 return !(value).equals(0.0);
223 }
224 throw new ValueException("Cannot coerce to boolean");
225 }
226
227 /**
228 * Get the first value, if it's a grid, or just pass-through.
229 *
230 * @param value - to get first of.
231 * @return - single value.
232 */
233 public static Object first(Object value) {
234 if (value instanceof Grid) {
235 return ((Grid) value).get(0, 0);
236 }
237 return value;
238 }
239
240 /**
241 * Cast value to Boolean.
242 *
243 * @param value - to cast.
244 * @return Boolean.
245 */
246 public static Boolean castAsBoolean(Object value) {
247 return (Boolean) value;
248 }
249
250 /**
251 * Cast value to Double.
252 *
253 * @param value - to cast.
254 * @return Double.
255 */
256 public static Double castAsDouble(Object value) {
257 return (Double) value;
258 }
259
260 /**
261 * Cast value to String.
262 *
263 * @param value - to cast.
264 * @return String.
265 */
266 public static String castAsString(Object value) {
267 return (String) value;
268 }
269
270 /**
271 * Cast value to F7Exception.
272 *
273 * @param value - to cast.
274 * @return F7Exception.
275 */
276 public static F7Exception castAsF7Error(Object value) {
277 return (F7Exception) value;
278 }
279
280 /**
281 * Cast value to Grid.
282 *
283 * @param value - to cast.
284 * @return Grid.
285 */
286 public static Grid<Object> castAsDataGrid(Object value) {
287 return (Grid<Object>) value;
288 }
289
290 /**
291 * Strings, Numbers, and Booleans have type precedence that is used when comparing across types.
292 *
293 * @param value to get precedence of.
294 * @return {@code 1} if Number,{@code 2} if String, {@code 3} if Boolean.
295 */
296 public static Integer getTypePrecedence(Object value) {
297 if (Objects.isNull(value)) {
298 return 0;
299 }
300 if (value instanceof Number) {
301 return 1;
302 }
303 if (value instanceof String) {
304 return 2;
305 }
306 return 3;
307 }
308}