[java] java.lang.ClassCastException : java.util.LinkedHashMap을 com.testing.models.Account로 캐스트 할 수 없습니다.

아래 오류가 발생합니다.

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.testing.models.Account

아래 코드로

final int expectedId = 1;

Test newTest = create();

int expectedResponseCode = Response.SC_OK;

ArrayList<Account> account = given().when().expect().statusCode(expectedResponseCode)
    .get("accounts/" + newTest.id() + "/users")
    .as(ArrayList.class);
assertThat(account.get(0).getId()).isEqualTo(expectedId);

내가 할 수없는 이유가 get(0)있습니까?



답변

문제는 잭슨에게서 나왔습니다. 역 직렬화 할 클래스에 대한 정보가 충분하지 않은 경우LinkedHashMap .

Jackson에의 요소 유형을 알리지 않았기 때문에 ArrayList으로 deserialize하려는 것을 알지 못합니다.ArrayListAccount의. 따라서 기본값으로 돌아갑니다.

대신을 사용 as(JsonNode.class)하고 ObjectMapper안심할 수있는 것보다 더 풍부한 방식으로을 처리 할 수 ​​있습니다. 이 같은:

ObjectMapper mapper = new ObjectMapper();

JsonNode accounts = given().when().expect().statusCode(expectedResponseCode)
    .get("accounts/" + newClub.getOwner().getCustId() + "/clubs")
    .as(JsonNode.class);


//Jackson's use of generics here are completely unsafe, but that's another issue
List<Account> accountList = mapper.convertValue(
    accounts,
    new TypeReference<List<Account>>(){}
);

assertThat(accountList.get(0).getId()).isEqualTo(expectedId);


답변

다음을 시도하십시오.

POJO pojo = mapper.convertValue(singleObject, POJO.class);

또는:

List<POJO> pojos = mapper.convertValue(
    listOfObjects,
    new TypeReference<List<POJO>>() { });

자세한 내용 은 LinkedHashMap 변환 을 참조하십시오.


답변

LinkedHashMap 개체의 수집 문제에 대한 JSON 배열을 완화 할 수있는 방법 CollectionTypeTypeReference. 이것이 내가하고 일한 것입니다 .

public <T> List<T> jsonArrayToObjectList(String json, Class<T> tClass) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    CollectionType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, tClass);
    List<T> ts = mapper.readValue(json, listType);
    LOGGER.debug("class name: {}", ts.get(0).getClass().getName());
    return ts;
}

을 사용하여 TypeReference여전히 LinkedHashMaps의 ArrayList를 얻었습니다. 즉 작동하지 않습니다 .

public <T> List<T> jsonArrayToObjectList(String json, Class<T> tClass) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<T> ts = mapper.readValue(json, new TypeReference<List<T>>(){});
    LOGGER.debug("class name: {}", ts.get(0).getClass().getName());
    return ts;
}


답변

비슷한 예외가 있었지만 (다른 문제)- java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.Document다행스럽게도 더 쉽게 해결되었습니다.

대신에

List<Document> docs = obj.get("documents");
Document doc = docs.get(0)

두 번째 줄에 오류가 발생하면 One 사용할 수 있습니다.

List<Document> docs = obj.get("documents");
Document doc = new Document(docs.get(0));


답변

일반적인 두 가지 방법으로 문제 해결

  1. 유형은 객체입니다.
public <T> T jsonToObject(String json, Class<T> type) {
        T target = null;
        try {
            target = objectMapper.readValue(json, type);
        } catch (Jsenter code hereonProcessingException e) {
            e.printStackTrace();
        }

        return target;
    }
  1. 유형은 컬렉션 랩 개체입니다.
public <T> T jsonToObject(String json, TypeReference<T> type) {
    T target = null;
    try {
        target = objectMapper.readValue(json, type);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    return target;
}


답변

XML을 deserialize하고 형식을 변환하는이 메서드가 있습니다.

public <T> Object deserialize(String xml, Class objClass ,TypeReference<T> typeReference ) throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    Object obj = xmlMapper.readValue(xml,objClass);
    return  xmlMapper.convertValue(obj,typeReference );
}

그리고 이것은 부름입니다 :

List<POJO> pojos = (List<POJO>) MyUtilClass.deserialize(xml, ArrayList.class,new TypeReference< List< POJO >>(){ });


답변

jackson을 사용하여 문자열에서 구체적인 클래스로 매핑하는 경우, 특히 일반 유형으로 작업하는 경우. 이 문제는 다른 클래스 로더로 인해 발생할 수 있습니다. 나는 아래 시나리오와 함께 한 번 만났습니다.

프로젝트 B는 라이브러리 A에 의존합니다.

라이브러리 A :

public class DocSearchResponse<T> {
 private T data;
}

외부 소스에서 데이터를 쿼리하고 jackson을 사용하여 구체적인 클래스로 변환하는 서비스가 있습니다.

public class ServiceA<T>{
  @Autowired
  private ObjectMapper mapper;
  @Autowired
  private ClientDocSearch searchClient;

  public DocSearchResponse<T> query(Criteria criteria){
      String resultInString = searchClient.search(criteria);
      return convertJson(resultInString)
  }
}

public DocSearchResponse<T> convertJson(String result){
     return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {});
  }
}

프로젝트 B :

public class Account{
 private String name;
 //come with other attributes
}

라이브러리의 ServiceA를 사용하여 쿼리를 만들고 데이터를 변환합니다.

public class ServiceAImpl extends ServiceA<Account> {

}

그리고 그것을 활용

public class MakingAccountService {
    @Autowired
    private ServiceA service;
    public void execute(Criteria criteria){

        DocSearchResponse<Account> result = service.query(criteria);
        Account acc = result.getData(); //  java.util.LinkedHashMap cannot be cast to com.testing.models.Account
    }
}

이는 LibraryA의 클래스 로더에서 jackson이 Account 클래스를로드 할 수없고 convertJsonjackson이 작업을 수행하도록 프로젝트 B의 메서드 를 재정의하기 때문에 발생합니다.

public class ServiceAImpl extends ServiceA<Account> {
        @Override
        public DocSearchResponse<T> convertJson(String result){
         return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {});
      }
    }
 }