从API获得的Json文件创建java对象



我想创建一个YuGiOh!游戏软件。所以,我的第一步是收集所有的卡片,制作一个卡片搜索引擎。

所以我调用了一个API来获取卡片数据,我不知道如何从中将它们映射到卡片类中,并将它们添加到卡片列表中,该列表将显示给用户,用户将选择他需要的卡片。

谢谢你对的帮助

package card;
import java.util.List;
public class card {
private int atk;
private int def;
private int level;
private String race;
private String attribute;
private String archetype;
private String imagePath;
private String name;
card(int atk, int def, int level, String name, String attribute, String imagePath)
{
this.atk = atk;
this.def = def;
this.level = level;
this.attribute = attribute;
this.imagePath = imagePath;
this.name = name;
}
public int getAtk() {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
public int getDef() {
return def;
}
public void setDef(int def) {
this.def = def;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}

public String getName() {
return name;
}
public void setName(String imagePath) {
this.name= name;
}
}
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import card.card;
public class API {

public void searchCard()
{
try 
{
URL url = new URL("https://db.ygoprodeck.com/api/v7/cardinfo.php?name=Dark%");

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("GET");

conn.connect();

//Check if connect is made
int responseCode = conn.getResponseCode();

// 200 OK
if (responseCode != 200) 
{
throw new RuntimeException("HttpResponseCode: " + responseCode);
} 
else 
{

ObjectMapper mapper = new ObjectMapper();
JsonNode cardData = mapper.readTree(url.openStream());
card[] cardList =  mapper.readValue(url.openStream(), card[].class);
System.out.print(cardList[0].getName());
//return cardData;
}
} 
catch (Exception e) 
{
e.printStackTrace();
}
}
}
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `[Lcard.card;` from Object value (token `JsonToken.START_OBJECT`)
at [Source: (sun.net.www.protocol.http.HttpURLConnection$HttpInputStream); line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1746)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1520)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1467)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.handleNonArray(ObjectArrayDeserializer.java:345)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:196)
at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4697)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3689)
at API.API.searchCard(API.java:46)
at APP.app.main(app.java:9)

以下是从api收集的数据示例。

{"data":[{"id":55289183,"name":"Capricious Darklord","type":"Effect Monster","desc":"During the Main Phase (Quick Effect): You can activate this effect; Tribute Summon 1 Fairy monster face-up. If this card is sent to the GY: You can make all monsters your opponent currently controls lose 500 ATK/DEF for each Fairy monster on the field, until the end of this turn. You can only use each effect of "Capricious Darklord" once per turn.","atk":0,"def":1600,"level":4,"race":"Fairy","attribute":"DARK","archetype":"Darklord","card_sets":[{"set_name":"2021 Tin of Ancient Battles","set_code":"MP21-EN117","set_rarity":"Common","set_rarity_code":"(C)","set_price":"0.88"},{"set_name":"Rise of the Duelist","set_code":"ROTD-EN023","set_rarity":"Common","set_rarity_code":"(C)","set_price":"0.99"}],"card_images":[{"id":55289183,"image_url":"https://storage.googleapis.com/ygoprodeck.com/pics/55289183.jpg","image_url_small":"https://storage.googleapis.com/ygoprodeck.com/pics_small/55289183.jpg"}],"card_prices":[{"cardmarket_price":"0.08","tcgplayer_price":"0.08","ebay_price":"0.99","amazon_price":"0.25","coolstuffinc_price":"0.49"}]},{"id":85325774,"name":"Charge Into a Dark World","type":"Spell Card","desc":"Target 1 Level 4 or lower Fiend monster in your GY; Special Summon it, then discard 1 Fiend monster. You can only activate 1 "Charge Into a Dark World" per turn.","race":"Normal","archetype":"Dark World","card_sets":[{"set_name":"2021 Tin of Ancient Battles","set_code":"MP21-EN206","set_rarity":"Common","set_rarity_code":"(C)","set_price":"0.96"},{"set_name":"Phantom Rage","set_code":"PHRA-EN063","set_rarity":"Common","set_rarity_code":"(C)","set_price":"0.99"}],"card_images":...

这里有很多问题。

您遇到的第一个问题是试图从JSON对象反序列化Java数组。不能这样做:只能将JSON对象反序列化为Java类的实例,或者将JSON数组反序列化为Java数组(或List(

您试图反序列化的JSON如下所示:

{
"data": [
{
"id": 55289183,
"name": "Capricious Darklord",
...
}

然而,在您的中

card[] cardList =  mapper.readValue(url.openStream(), card[].class);

您正试图将其反序列化为如下所示:

[
{
"id": 55289183,
"name": "Capricious Darklord",
...
]

您需要做的是编写一个具有data属性的Java小类,并将数据反序列化为该类的实例。这个类看起来如下:

public class CardList {

private card[] data;
public card[] getData() {
return data;
}
public void setData(card[] data) {
this.data = data;
}
}

然后将反序列化JSON的代码调整为以下代码:

CardList cardList = mapper.readValue(url.openStream(), CardList.class);
System.out.print(cardList.getData()[0].getName());

您将遇到的下一个问题是,JSON数据包含不在card类中的属性,例如idtypedesc。Jackson会抱怨它不知道如何处理在Java类中找不到的属性的数据,但你可以通过添加行来告诉它忽略这些属性

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

紧接在创建ObjectMapper的那个之后。您可能还需要添加以下行:

import com.fasterxml.jackson.databind.DeserializationFeature;

您可能得到的下一个错误是Cannot construct instance of 'com.example.card' (no Creators, like default constructor, exist)。消除这种情况的最简单方法是删除card类中的构造函数:然后Jackson将通过调用自动生成的零参数构造函数来创建card对象。

在进行了所有这些更改之后,您应该发现您的代码正在运行,并且不会抛出异常,而是打印出null。但它为什么要这么做呢?仔细查看card类中的setName设置器:

public void setName(String imagePath) {
this.name= name;
}

请注意,方法参数的名称为imagePath。这应该是name。因为方法参数的名称错误,所以传递给该方法的值将被忽略,并且行this.name= name最终执行this.name = this.name,这不是很有用。请注意,像Eclipse、NetBeans和IntelliJ IDEA这样的IDE可以为您生成getter和setter,这样可以避免类似的错误。

我对您的代码进行了这些更改,它能够反序列化您的JSON数据,并让程序打印出第一张卡的名称。

错误cannot deserialize value of type [Lcard.card; from Object value

意味着Jackson不能从不是数组而是对象的JSON值反序列化card数组。

它遇到的JSON对象是

{
"data": [ {card}, {card}, {card} ]
}

因此您必须映射到一个对象,该对象包含data字段中的卡列表/阵列。例如,您可以创建一个类似的类

class Response {
public data: card[]
}

然后要求Jackson对其进行反序列化,然后通过data字段访问卡。


[Lcard的意思是:[是一个数组类型,Lcard表示有一个名为card的类(L(。即card[]

顺便说一句,启动类名UpperCase也是很常见的。我建议你坚持这样做,否则习惯Java的人会被你的代码弄糊涂。

如果您不想自己编写所有这些Java类,您可以顺便找到许多JSON到Java/Pojo生成器(例如。https://www.jsonschema2pojo.org/)在互联网上,他们可以为你生成类,你所需要做的就是将它们复制到你的源代码中。非常适合这样的大回复。

最新更新