将 JSON 数组字符串转换为 java 列表的通用方法
Generic Method to Convert JSON Array String to List in java
我一直在尝试为我的项目创建一个实用程序,让您可以从 JSON 相同的字符串制作 List<DesiredTypeClass>
。
以下是我当前的实现:
public static <T> List<?> stringToClassList(String data, Class<T> convertType, ObjectMapper mapper) {
if (!StringUtils.isBlank(data)) {
try {
if (mapper.readTree(data).size() != 0) {
return Arrays.asList(mapper.convertValue(mapper.readTree(data), Array.newInstance(convertType, 0).getClass()));
}
}
catch (JsonProcessingException processingException) {
LOGGER.error("Error coverting String to Json, Error: {}", processingException);
throw new UnrecoverableRequestException(processingException);
}
}
return new ArrayList<>();
}
要调用这个方法,你应该有:arrayString,一个classType(例如:使用MyDto.class获取List)和一个ObjectMapper实例;
围绕这个写一个测试用例,我在结果中发现了额外的数组大括号:
java.lang.AssertionError:
Expected :[{"startDate":"2020-12-01","endDate":"2020-12-02"},{"startDate":"2020-12-10","endDate":"2020-12-11"}]
Actual :[[{"startDate":"2020-12-01","endDate":"2020-12-02"},{"startDate":"2020-12-10","endDate":"2020-12-11"}]]
这是失败测试的简化版本:
@Test
public void testStringToClassList() {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode firstNode = new ObjectNode(JsonNodeFactory.instance);
firstNode.set("startDate", JsonNodeFactory.instance.textNode("2020-12-01"));
firstNode.set("endDate", JsonNodeFactory.instance.textNode("2020-12-02"));
ObjectNode secondNode = new ObjectNode(JsonNodeFactory.instance);
secondNode.set("startDate", JsonNodeFactory.instance.textNode("2020-12-10"));
secondNode.set("endDate", JsonNodeFactory.instance.textNode("2020-12-11"));
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
arrayNode.add(firstNode);
arrayNode.add(secondNode);
String arrayString = "[{\"startDate\":\"2020-12-01\",\"endDate\":\"2020-12-02\"},{\"startDate\":\"2020-12-10\",\"endDate\":\"2020-12-11\"}]";
List<?> objectList = ObjectNodeUtils.stringToClassList(arrayString, Object.class, objectMapper);
Assert.assertEquals(arrayNode, objectMapper.valueToTree(objectList));
}
我了解到问题与以下方面有关:
Arrays.asList(mapper.convertValue(mapper.readTree(data), Array.newInstance(convertType, 0).getClass()))
关于如何在此处获取列表的任何想法? (我不太习惯编写通用代码,但这似乎是个不错的选择)
不包装 objectMapper 的转换值结果。
public static <T> List<?> stringToClassList(String data, Class<T> convertType, ObjectMapper mapper) {
if (!StringUtils.isBlank(data)) {
try {
if (mapper.readTree(data).size() != 0) {
return mapper.convertValue(mapper.readTree(data), new TypeReference<List<T>>(){});
}
}
catch (JsonProcessingException processingException) {
LOGGER.error("Error coverting String to Json, Error: {}", processingException);
throw new UnrecoverableRequestException(processingException);
}
}
return Collections.EMPTY_LIST;
}
不要重新发明轮子:
public static <T> List<T> stringToClassList(String data, Class<T> convertType, ObjectMapper mapper) {
return mapper.readValue(data, mapper.getTypeFactory().constructCollectionType(List.class, convertType));
}
另请注意将 return 类型从 List<?>
(不太有用)修复为 List<T>
(有用)。
你的测试方法还可以简化和改进:
@Test
public void testStringToClassList() {
String input = "[\"foo\", \"bar\"]";
List<String> expected = Arrays.asList("foo", "bar");
Assert.assertEquals(expected, stringToClassList(input, String.class));
}
我一直在尝试为我的项目创建一个实用程序,让您可以从 JSON 相同的字符串制作 List<DesiredTypeClass>
。
以下是我当前的实现:
public static <T> List<?> stringToClassList(String data, Class<T> convertType, ObjectMapper mapper) {
if (!StringUtils.isBlank(data)) {
try {
if (mapper.readTree(data).size() != 0) {
return Arrays.asList(mapper.convertValue(mapper.readTree(data), Array.newInstance(convertType, 0).getClass()));
}
}
catch (JsonProcessingException processingException) {
LOGGER.error("Error coverting String to Json, Error: {}", processingException);
throw new UnrecoverableRequestException(processingException);
}
}
return new ArrayList<>();
}
要调用这个方法,你应该有:arrayString,一个classType(例如:使用MyDto.class获取List)和一个ObjectMapper实例;
围绕这个写一个测试用例,我在结果中发现了额外的数组大括号:
java.lang.AssertionError:
Expected :[{"startDate":"2020-12-01","endDate":"2020-12-02"},{"startDate":"2020-12-10","endDate":"2020-12-11"}]
Actual :[[{"startDate":"2020-12-01","endDate":"2020-12-02"},{"startDate":"2020-12-10","endDate":"2020-12-11"}]]
这是失败测试的简化版本:
@Test
public void testStringToClassList() {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode firstNode = new ObjectNode(JsonNodeFactory.instance);
firstNode.set("startDate", JsonNodeFactory.instance.textNode("2020-12-01"));
firstNode.set("endDate", JsonNodeFactory.instance.textNode("2020-12-02"));
ObjectNode secondNode = new ObjectNode(JsonNodeFactory.instance);
secondNode.set("startDate", JsonNodeFactory.instance.textNode("2020-12-10"));
secondNode.set("endDate", JsonNodeFactory.instance.textNode("2020-12-11"));
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
arrayNode.add(firstNode);
arrayNode.add(secondNode);
String arrayString = "[{\"startDate\":\"2020-12-01\",\"endDate\":\"2020-12-02\"},{\"startDate\":\"2020-12-10\",\"endDate\":\"2020-12-11\"}]";
List<?> objectList = ObjectNodeUtils.stringToClassList(arrayString, Object.class, objectMapper);
Assert.assertEquals(arrayNode, objectMapper.valueToTree(objectList));
}
我了解到问题与以下方面有关:
Arrays.asList(mapper.convertValue(mapper.readTree(data), Array.newInstance(convertType, 0).getClass()))
关于如何在此处获取列表的任何想法? (我不太习惯编写通用代码,但这似乎是个不错的选择)
不包装 objectMapper 的转换值结果。
public static <T> List<?> stringToClassList(String data, Class<T> convertType, ObjectMapper mapper) {
if (!StringUtils.isBlank(data)) {
try {
if (mapper.readTree(data).size() != 0) {
return mapper.convertValue(mapper.readTree(data), new TypeReference<List<T>>(){});
}
}
catch (JsonProcessingException processingException) {
LOGGER.error("Error coverting String to Json, Error: {}", processingException);
throw new UnrecoverableRequestException(processingException);
}
}
return Collections.EMPTY_LIST;
}
不要重新发明轮子:
public static <T> List<T> stringToClassList(String data, Class<T> convertType, ObjectMapper mapper) {
return mapper.readValue(data, mapper.getTypeFactory().constructCollectionType(List.class, convertType));
}
另请注意将 return 类型从 List<?>
(不太有用)修复为 List<T>
(有用)。
你的测试方法还可以简化和改进:
@Test
public void testStringToClassList() {
String input = "[\"foo\", \"bar\"]";
List<String> expected = Arrays.asList("foo", "bar");
Assert.assertEquals(expected, stringToClassList(input, String.class));
}