【发布时间】:2021-07-08 21:45:46
【问题描述】:
我正在尝试从包含地图的非标准表示形式作为列之一的 csv 字符串反序列化 MyObject 数组(通过 Lombok 使用构建器模式和 @Jacksonized)。
我的对象:
@JsonPropertyOrder({
"strField",
"mapField",
})
@Getter
@Jacksonized
@Builder(toBuilder = true)
@EqualsAndHashCode
@ToString
public class MyObject {
private final String strField;
@Builder.Default
private final Map<String, Float> mapField = new HashMap<>();
}
具有非标准 mapField 表示的示例 csv:
strField,mapField
abc,"key1=2.0;key2=3.0"
我正在使用 mixin 来尝试在不重写整个对象的情况下实现这一点:
@JsonPropertyOrder({
"strField",
"mapField",
})
public abstract class MyObjectDeserializerMixin {
@JsonDeserialize(using = StringToMapDeserializer.class)
private Map<String, Float> mapField;
}
..正如您在上面看到的,它指向自定义反序列化器:
public class StringToMapDeserializer extends JsonDeserializer<Map<String, Float>> {
@Override
public Map<String, Float> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String csvFormattedMap = jsonParser.getText().trim();
return Arrays.stream(csvFormattedMap.split(";"))
.map(keyValue -> keyValue.split("="))
.collect(Collectors.toMap(keyValue -> keyValue[0], keyValue -> Float.parseFloat(keyValue[1])));
}
}
而且,总而言之,我正在配置和使用我的CsvMapper,如下所示:
CsvMapper csvMapper = new CsvMapper();
csvMapper.addMixIn(MyObject.class, MyObjectDeserializerMixin.class);
CsvSchema csvSchema = csvMapper
.schemaFor(MyObject.class)
.withHeader();
ObjectReader csvReader = csvMapper.readerFor(MyObject.class).with(csvSchema);
List<MyObject> myObjects = csvReader.<MyObject>readValues(theCsvString).readAll();
但是,我遇到了以下异常:
com.fasterxml.jackson.databind.exc.MismatchedInputException: 不能 构造
java.util.LinkedHashMap的实例(尽管至少有一个 Creator 存在):没有字符串参数构造函数/工厂方法 从 [来源: (字符串读取器);行:2,列:53](通过参考链: myPackage.MyObject$MyObjectBuilder["mapField"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1432)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1062)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:371)
at com.fasterxml.jackson.databind.deser.ValueInstantiator.createFromString(ValueInstantiator.java:258)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:357)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeSetAndReturn(MethodProperty.java:158)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:269)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:193)
at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1719)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1261)
...
堆栈跟踪似乎正在尝试使用BuilderBasedDeserializer,它尝试将MapDeserializer.java 用于映射,因此它似乎不知道我的自定义反序列化器。我使用了一个非常相似的工作流程和自定义 serializer 来编写相同的 csv,所以我很困惑为什么这不起作用。解决此问题的下一步是什么?
【问题讨论】:
-
将mixin添加到
MyObjectBuilder.class而不是MyObject.class时是否有效? -
@JanRieke 使用
csvMapper.addMixIn(MyObject.MyObjectBuilder.class, MyObjectDeserializerMixin.class);不起作用,不。 -
奇怪。我只是将您的示例 c&p'ed 到我的 IDE 中,当我将 mixin 添加到构建器时它可以工作。您在此处的示例代码中是否省略了某些内容?使用 Lombok 1.18.20 和 Jackson 2.12.2。
-
我确实尝试对其进行了一些清理 - 例如,
MyObject中有更多字段,并且名称不同..让我尝试将我的代码简化为这个孤立的示例.. 另外我使用的 jackson 和 lombok 版本是 jackson 2.10.3 和 lombok 1.18.16 -
由于该解决方案对我有用,我添加了一个答案。让我们继续讨论,让它适用于您的案例。