Кастинг LinkedHashMap для сложного объекта
У меня есть приложение, которое хранит некоторые данные в DynamoDB, используя Jackson для сортировки моего сложного объекта в JSON.
Например, объект, который я сортирую, может выглядеть так:
private String aString;
private List<SomeObject> someObjectList;
Где SomeObject может выглядеть так:
private int anInteger;
private SomeOtherObject;
и SomeOtherObject может выглядеть так:
private long aLong;
private float aFloat;
Это хорошо, что объект не сортируется без проблем и хранится в DB как строка JSON.
Когда придет время для извлечения данных из DynamoDB, Джексон автоматически извлекает JSON и преобразует его обратно... ЗА ИСКЛЮЧЕНИЕМ, что 'someObjectList' возвращается как List<LinkedHashMap>
не как List<SomeObject>
! Это стандартное поведение для Джексона, это не ошибка, что это происходит.
Итак, теперь это приводит к проблеме. Моя база кода думает, что имеет дело с 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" .
Ответы
Ответ 1
Вы можете использовать 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, вместо этого в качестве промежуточного шага используется последовательность событий в памяти.
Ответ 2
Есть хорошее решение этой проблемы:
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();
Ответ 3
У меня была похожая проблема, где у нас есть объект 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>>() { });