Подтвердить что ты не робот

Кастинг 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" .

4b9b3361

Ответ 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>>() { });