Created
January 23, 2024 13:51
-
-
Save richardstephens/fd6e8a59906431f7f16755cc98fe7363 to your computer and use it in GitHub Desktop.
Convert a string of output for an SQL query into an array of POJOs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package cloud.gallium.lib.testutils; | |
import lombok.SneakyThrows; | |
import java.lang.reflect.Constructor; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.UUID; | |
public class RowStringsToClasses { | |
// This method converts a string of output from a database query | |
// into a list of objects of the given class. | |
// | |
// Expected input format: | |
// a | b | c | |
// ---+---+--- | |
// 1 | 2 | 3 | |
// | |
@SneakyThrows | |
public static <T> List<T> mockRows(String in, Class<T> clazz) { | |
var lines = in.lines().filter(l -> l.trim().length() > 0).toList(); | |
var header = | |
Arrays.stream(lines.get(0).split("\\|")) | |
.map(String::trim) | |
.map(s -> toCamelCase(s)) | |
.toList(); | |
var rows = lines.subList(2, lines.size()); | |
Constructor<T> constructorToUse = null; | |
for (var constructor : (Constructor<T>[]) clazz.getConstructors()) { | |
if (constructorToUse == null | |
|| constructor.getParameterCount() > constructorToUse.getParameterCount()) { | |
constructorToUse = constructor; | |
} | |
} | |
Map<String, Class> typeToUse = new HashMap<>(); | |
Map<String, Integer> indexToUse = new HashMap<>(); | |
var parameters = constructorToUse.getParameters(); | |
for (var name : header) { | |
boolean found = false; | |
for (int idx = 0; idx < parameters.length; idx++) { | |
var p = parameters[idx]; | |
if (p.getName().equals(name)) { | |
typeToUse.put(name, p.getType()); | |
indexToUse.put(name, idx); | |
} | |
found = true; | |
} | |
if (!found) { | |
throw new IllegalArgumentException("No parameter found for " + name); | |
} | |
} | |
List<T> result = new ArrayList<>(); | |
for (var row : rows) { | |
var rowParts = Arrays.stream(row.split("\\|")).map(String::trim).toList(); | |
var args = new Object[constructorToUse.getParameterCount()]; | |
for (int idx = 0; idx < header.size(); idx++) { | |
var name = header.get(idx); | |
var valueStr = rowParts.get(idx); | |
var type = typeToUse.get(name); | |
var index = indexToUse.get(name); | |
Object value = parseValueStr(valueStr, type); | |
args[index] = value; | |
} | |
result.add(constructorToUse.newInstance(args)); | |
} | |
return result; | |
} | |
private static String toCamelCase(String s) { | |
String[] parts = s.split("_"); | |
StringBuilder camelCaseString = new StringBuilder(parts[0].toLowerCase()); | |
for (int i = 1; i < parts.length; i++) { | |
camelCaseString.append(parts[i].substring(0, 1).toUpperCase()); | |
camelCaseString.append(parts[i].substring(1).toLowerCase()); | |
} | |
return camelCaseString.toString(); | |
} | |
private static Object parseValueStr(String valueStr, Class type) { | |
if (type == String.class) { | |
return valueStr; | |
} else if (type == UUID.class) { | |
return UUID.fromString(valueStr); | |
} else if (type == Integer.class) { | |
return Integer.parseInt(valueStr); | |
} else if (type == Long.class) { | |
return Long.parseLong(valueStr); | |
} else if (type == Boolean.class) { | |
if (valueStr.equals("t")) { | |
return true; | |
} else if (valueStr.equals("f")) { | |
return false; | |
} else { | |
throw new IllegalArgumentException("Unknown boolean value " + valueStr); | |
} | |
} else if (type == Double.class) { | |
return Double.parseDouble(valueStr); | |
} else if (type == Float.class) { | |
return Float.parseFloat(valueStr); | |
} else { | |
throw new IllegalArgumentException("Unknown type " + type); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment