将LinkedHashMap转换为复杂对象

101

我有一个应用程序,使用Jackson将我的复杂对象序列化为JSON并将其存储在DynamoDB中。

例如,我要序列化的对象可能如下所示:

private String aString;
private List<SomeObject> someObjectList;

其中SomeObject可能长这样:

private int anInteger;
private SomeOtherObject;

而 SomeOtherObject 可能是这个样子:

private long aLong;
private float aFloat; 

这个对象可以很好地序列化并作为JSON字符串存储在数据库中。

但当从DynamoDB检索数据时,Jackson会自动检索JSON并将其转换回来...除了'someObjectList'会被返回为List<LinkedHashMap>而不是List<SomeObject>!对于Jackson来说,这是标准行为,这不是错误。

现在遇到了一个问题。我的代码库认为它正在处理List<SomeObject>,但实际上它正在处理List<LinkedHashMap>!我的问题是如何将LinkedHashMap还原成'SomeObject'。显然,这是一个手动的过程,但我的意思是我甚至不能提取值。

如果我这样做:

for (LinkedHashMap lhm : someObjectList) {
    // Convert the values back
}

我遇到了编译错误,提示我someObjectList的类型为'SomeObject'而非LinkedHashMap。

如果我这样做:

for (SomeObject lhm : someObjectList) {
    // Convert the values back
}

我收到一个运行时错误,告诉我LinkedHashMap无法转换为'SomeObject'。


convertValue 对我来说起作用了 - Gaurav
6个回答

241

您可以使用ObjectMapper.convertValue(),逐个值或甚至整个列表进行转换。但您需要知道要进行转换的类型:

POJO pojo = mapper.convertValue(singleObject, POJO.class);
// or:
List<POJO> pojos = mapper.convertValue(listOfObjects, new TypeReference<List<POJO>>() { });

这在功能上与您执行以下操作相同:

byte[] json = mapper.writeValueAsBytes(singleObject);
POJO pojo = mapper.readValue(json, POJO.class);

但避免将数据实际序列化为JSON,而是使用内存中的事件序列作为中间步骤。


太棒了。我唯一需要做的就是确保POJO类包含一个默认构造函数(如果存在其他参数化构造函数)。 - Gnana
我的意思是,对于第一个示例,类型必须在设计时已知。您不能仅将对象的类型传递给(反)序列化方法,这是一个问题,如果您正在制作一种方法来(反)序列化任何类型的类。对于第二个示例,您可以只需使用.getClass()进行序列化,并传入类型进行反序列化。 - Bo Søborg Petersen
@BoSøborgPetersen 好的,TypeReference确实如此,但是您可以使用TypeFactoryconstructCollectionType(elementType)或类似方法)构造List类型,这并不是一般性限制。 - StaxMan
如果我传递一个通用类型,那么TypeReference ref = new TypeReference<T>(){}; mapper.readValue(source, ref);怎样? - Bron Davies
5
给新读者的一条快速提示: 代码片段中的TypeReference类来自于 "com.fasterxml.jackson.core.type.TypeReference"。 - AliReza
显示剩余4条评论

12

我曾遇到类似的问题,我们有一个包含值列表的GenericResponse对象。

 ResponseEntity<ResponseDTO> responseEntity = restTemplate.exchange(
                redisMatchedDriverUrl,
                HttpMethod.POST,
                requestEntity,
                ResponseDTO.class
        );

使用objectMapper有助于将LinkedHashMap转换为相应的DTO对象。

 ObjectMapper mapper = new ObjectMapper();

 List<DriverLocationDTO> driverlocationsList = mapper.convertValue(responseDTO.getData(), new TypeReference<List<DriverLocationDTO>>() { });

3
public static <T> List<T> getObjectList(final String json, final Class<T> cls) 
{
    return objectMapper
        .readValue(json, objectMapper.getTypeFactory()
        .constructCollectionType(ArrayList.class, cls));
}

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community
这个解决方案真的帮助我泛化了我的 API 调用,这些调用必须返回我的类类型对象的列表。 - ychaulagain

0
我使用com.fasterxml.jackson.databind.ObjectMapper将LinkedHashMap映射为Json字符串,然后再将Json字符串转换为对象。
Map<String, String> mappingValue
OBJECTA a = objectMapper.readValue(toJson(mappingValue), OBJECTA.class);

public static String toJson(Object object) {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    String jsonString = "";

    try {
        jsonString = mapper.writeValueAsString(object);
    } catch (JsonProcessingException var4) {
        var4.printStackTrace();
        jsonString = "Can't build json from object";
    }

    return jsonString;
}

0

这个问题有一个很好的解决方案:

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper objectMapper = new ObjectMapper();

***DTO premierDriverInfoDTO = objectMapper.convertValue(jsonString, ***DTO.class); 

Map<String, String> map = objectMapper.convertValue(jsonString, Map.class);

为什么会出现这个问题?我猜测在将字符串转换为对象时,您没有指定特定类型,而是使用了一个带有泛型类型的类,例如 User<T>。
也许还有另一种解决方法,可以使用 Gson 而不是 ObjectMapper。(或者参见此处 使用 GSON 反序列化泛型类型
Gson gson = new GsonBuilder().create();

Type type = new TypeToken<BaseResponseDTO<List<PaymentSummaryDTO>>>(){}.getType();

BaseResponseDTO<List<PaymentSummaryDTO>> results = gson.fromJson(jsonString, type);

BigDecimal revenue = results.getResult().get(0).getRevenue();

2
同时也请提供解释 :) - Mohit Motwani
虽然这段代码片段可能是解决方案,但包括解释真的有助于提高您的帖子质量。请记住,您正在回答未来读者的问题,而这些人可能不知道您的代码建议原因。 - Johan
@Johan 好的,谢谢你的提醒。我在 Stack Overflow 上回答问题还是个新手,所以以后会做得更好。 - Donald Choi

-1
首先,您需要将LinkedHashMap转换为JsonString,然后才能将其转换为复杂对象。

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接