java.lang.ClassCastException:java.util.LinkedHashMapをcom.testing.models.Accountにキャストできません


84

以下のエラーが発生します:

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)か?


にキャストできない?エラーメッセージの残りは何ですか?
オリバーチャールズワース2015

1
@OliverCharlesworthもスタックトレース全体を追加しました
情熱的なエンジニア

2
Accountですか?なぜマップからキャストしようとしているのですか?
デイブニュートン

ライブラリに慣れていない可能性がある私たちにとって、このgiven()メソッドが静的にインポートされるクラスを教えてください。
マークピーターズ

@DaveNewtonAccountは、Dropwizardのモデルで、次を使用しますcom.fasterxml.jackson.databind.annotations
Passionate Engineer

回答:


108

問題はジャクソンから来ています。デシリアライズするクラスに関する十分な情報がない場合は、を使用しLinkedHashMapます。

あなたの要素型のジャクソンに通知していないのでArrayList、それはあなたに非直列化することを知らない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);

応答をasString()に設定することもでき、余分な変換を行う必要がなくなります。readValueは最初の引数として文字列を受け入れます。
BIGDeutsch 2016年

@BIGDeutsch:これをもう一度見てみるconvertValueと、1つのステップで実行できる場合は、トークンに戻す必要はありませんでした。文字列に移動することもできます。
マークピーターズ

44

次のことを試してください。

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

または:

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

詳細については、LinkedHashMapの変換を参照してください。


3
「convertValue」を表示するための+1。jsonから特定のプロパティをリストとして読み取る必要がある場合がありました。これはまさに私が必要としていたものです。
GameSalutes 2017年

28

LinkedHashMapオブジェクトのコレクションに対するJSON配列の問題軽減する方法は、CollectionTypeではなくを使用することでした TypeReference。これは私がやったことと働いたことです:

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;
}

1
私の問題も保存しました。ありがとうございました!
ウラジミールギレビッチ2017年

1
+1、あなたの場合の違いは、メソッド自体が汎用であるためT、TypeTokenを介して具体化できないことでした。これは通常は簡単です。個人的には、Guavaのヘルパーが好きです。なぜなら、それはまだタイプセーフであり、どのコンテナータイプにも固有ではないからですreturn new TypeToken<List<T>>(){}.where(new TypeParameter<T>(){}, tClass)。しかし、ジャクソンはTypeTokensをとらないので、必要.getType()です。
マークピーターズ

私の問題も保存しました。ありがとうございました!
Shashank

6

私は同様の例外を持っていました(しかし異なる問題)- java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.Documentそして幸いにもそれはより簡単に解決されました:

の代わりに

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

2行目にエラーが発生します。

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

1

一般的な2つのメソッド解析で問題を解決します

  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;
}

0

XMLを逆シリアル化し、型を変換するための次のメソッドがあります。

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 >>(){ });

0

ジャクソンを使用して文字列から具象クラスにマップする場合、特にジェネリック型を使用する場合。この問題は、クラスローダーが異なるために発生する可能性があります。私は以下のシナリオで一度会った:

プロジェクト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クラスをロードできずconvertJson、プロジェクトBのメソッドをオーバーライドして、jacksonにジョブを実行させるために発生します。

public class ServiceAImpl extends ServiceA<Account> {
        @Override
        public DocSearchResponse<T> convertJson(String result){
         return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {});
      }
    }
 }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.