Retrofit, parsing JSON null exception at response

纵饮孤独 提交于 2019-12-25 08:12:03

问题


I'm using Retrofit in my app. I've got JSON response which looks like this:

{
  "data": {
    "list": [
      {
        "id": 58,
        "beacon_id": "58",
        "bridge_id": null,
        "mesh_id": null,
        "name": "eon_3c",
        "location": "abcdlk",
        "mac_address": "3c:cf:82:8a:e7:fe",
        "firmware": "2.1",
        "pcb_revision": "2.0",
        "battery_level": "99",
        "password": "0000",
        "ib": {
          "turn_on": "1",
          "major": "33",
          "minor": "344",
          "tx_power": "7",
          "interval": "400",
          "uuid": "dae19960-18ea-11e5-8ff0-0002a5d5c521",
          "secure_uuid": "0"
        },
        "euid": {
          "turn_on": "0",
          "namespace": null,
          "instance": null,
          "tx_power": null,
          "interval": null
        },
        "eeid": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null
        },
        "eurl": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null,
          "url": null
        },
        "etlm": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null
        },
        "assigned_bridge_id": null
      },
      {
        "id": 56,
        "beacon_id": "56",
        "bridge_id": null,
        "mesh_id": null,
        "name": "Eon_e6",
        "location": "test",
        "mac_address": "e6:f5:8a:94:b8:c7",
        "firmware": "2.1",
        "pcb_revision": "2.0",
        "battery_level": null,
        "password": "0000",
        "ib": {
          "turn_on": "1",
          "major": "2591",
          "minor": "0",
          "tx_power": "10",
          "interval": "2593",
          "uuid": "dae19960-18ea-11e5-8ff0-0002a5d5c521",
          "secure_uuid": "0"
        },
        "euid": {
          "turn_on": "0",
          "namespace": null,
          "instance": null,
          "tx_power": null,
          "interval": null
        },
        "eeid": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null
        },
        "eurl": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null,
          "url": null
        },
        "etlm": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null
        },
        "assigned_bridge_id": null
      },
      {
        "id": 57,
        "beacon_id": "57",
        "bridge_id": "13",
        "mesh_id": "278",
        "name": "Marta B",
        "location": "lk",
        "mac_address": "e1:4b:64:c3:80:e2",
        "firmware": "2.1",
        "pcb_revision": "2.0",
        "battery_level": "97",
        "password": "0000",
        "ib": {
          "turn_on": "1",
          "major": "325",
          "minor": "10",
          "tx_power": "8",
          "interval": "610",
          "uuid": "dae19960-18ea-11e5-8ff0-0002a5d5c521",
          "secure_uuid": "0"
        },
        "euid": {
          "turn_on": "0",
          "namespace": null,
          "instance": null,
          "tx_power": null,
          "interval": null
        },
        "eeid": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null
        },
        "eurl": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null,
          "url": null
        },
        "etlm": {
          "turn_on": "0",
          "tx_power": null,
          "interval": null
        },
        "assigned_bridge_id": null
      }
    ]
  },
  "ver": 1,
  "time": 1475671202,
  "status": 1,
  "status_msg": ""
}

Here's my response class:

public class BeaconResponse {
    @Expose
    public Data data;
    @Expose
    public int ver;
    @Expose
    public int time;
    @Expose
    public int status;
    @Expose
    public String statusMsg;
}

In the Data class I've got List with List objects. I know it's bad naming, sorry.

public class Data extends Model {
    @Column
    public java.util.List<List> list;
}

And here's my List.class:

public class List {

    public Integer id;
    public String beaconId;
    public String bridgeId;
    public String meshId;
    public String name;
    public String location;
    public String macAddress;
    public String firmware;
    public String pcbRevision;
    public String batteryLevel;
    public String password;
    public Ib ib;
    public Euid euid;
    public Eeid eeid;
    public Eurl eurl;
    public Etlm etlm;
    public int assignedBridgeId;
}

I think it should work, but it doesn't. When I try to map it to the model class I'm getting 3 objects ResponseList.size = 3 but all fields are null: data, statusMSG and so on. Can you tell me why this is? Thanks in advance for helping :)

My interface :

@GET("/api/mobile/{language}/{apiVersion}/beacons/list")
void beaconsList(Callback<BasicResponse<BeaconsListResponse>> callback);

public class BeaconsListResponse {
    @Expose
    public List<BeaconResponse> list;
}

Here's my retrofit call:

@Subscribe
public void getUserBeacons(GetBeaconsListCommand command) {
    Callback<BasicResponse<BeaconsListResponse>> callback = new Callback<BasicResponse<BeaconsListResponse>>() {
        @Override
        public void success(BasicResponse<BeaconsListResponse> basicResponse, Response response) {
            if (ResponseStatus.SUCCESS.statusCode == basicResponse.status)
                EventBus.post(new BeaconsListFetchedEvent(basicResponse.data));
            else
                EventBus.post(new NetworkFailureEvent(ResponseStatus.getByStatus(basicResponse.status), basicResponse.status_msg));
        }

        @Override
        public void failure(RetrofitError error) {
        }
    };
    service.beaconsList(callback);
}

Main response class:

public class BasicResponse<T> {
    @Expose
    public T list;
    @Expose
    public int ver;
    @Expose
    public long time;
    @Expose
    public byte status;
    @Expose
    public String status_msg;
}

回答1:


Perhaps you should create your response class like this:

@SerializedName("list")
@Expose
private List<Data> list = new ArrayList<Data>();

Try creating your Response class through this tool:

http://www.jsonschema2pojo.org/




回答2:


The issue is that your Java classes do not mimic your JSON schema. You Java classes need to match the JSON schema exactly, or GSON will not be able to deserialize the data. This should better represent your schema:

public class StandardResponse<T> {

    @SerializedName("data") public T data;
    @SerializedName("ver") public Integer version;
    @SerializedName("time") public Long time;
    @SerializedName("status") public Integer status;
    @SerializedName("status_msg") public String statusMessage;

}

Then you can implement a ListData class that contains a List:

public class ListData<T> {

    @SerializedName("list") public List<T> list;

}

Then on to your Beacon class:

public class Beacon {

    @SerializedName("id") public Integer id;
    @SerializedName("beacon_id") public String beaconID;
    @SerializedName("bridge_id") public String bridgeID;
    @SerializedName("mesh_id") public String meshID;
    @SerializedName("name") public String name;
    @SerializedName("location") public String location;
    @SerializedName("mac_address") public String macAddress;
    @SerializedName("firmware") public String firmware;
    @SerializedName("pcb_revision") public String pcbRevision;
    @SerializedName("battery_level") public String batteryLevel;
    @SerializedName("password") public String password;
    @SerializedName("ib") public Ib ib;
    @SerializedName("euid") public Euid euid;
    @SerializedName("eeid") public Eeid eeid;
    @SerializedName("eurl") public Eurl eurl;
    @SerializedName("etlm") public Etlm etlm;
    @SerializedName("assigned_bridge_id") public String assignedBridgeID;

}

I will skip your Ib, Euid, Edid, Eurl and Etlm classes, as they should not be too difficult to implement based on the classes above.


With these classes, your Retrofit Callback should look like this:

@GET("/api/mobile/{language}/{apiVersion}/beacons/list")
void getBeacons(Callback<StandardResponse<ListData<Beacon>> callback);

And finally, you can obtain your list of Beacon objects from the callback like so:

service.getBeacons(new Callback<StandardResponse<ListData<Beacon>>> {

    @Override
    public void success(StandardResponse<ListData<Beacon>> standard, Response response) {
        Log.d(TAG, "Status: " + standard.status + "; with message: " + standard.statusMessage);
        List<Beacon> beacons = standard.data.list;

        for(Beacon beacon: beacons) {
            Log.d(TAG, "Beacon ID: " + beacon.id);
        }
    }

    @Override
    public void failure(RetrofitError error) {
        // TODO: implement error handling
    }

});

Based on your sample JSON, the above code should print the following in logcat:

Status: 1, with message:
Beacon ID: 58
Beacon ID: 56
Beacon ID: 57

Update

Here are the Ib, Euid, Edid, Eurl and Etlm classes:

public class Ib {

    @SerializedName("turn_on") public String turnOn;
    @SerializedName("major") public String major;
    @SerializedName("minor") public String minor;
    @SerializedName("tx_power") public String txPower;
    @SerializedName("interval") public String interval;
    @SerializedName("uuid") public String uuid;
    @SerializedName("secure_uuid") public String uuidSecure;

}

public class Euid {

    @SerializedName("turn_on") public String turnOn;
    @SerializedName("namespace") public String nameSpace;
    @SerializedName("instance") public String instance;
    @SerializedName("tx_power") public String txPower;
    @SerializedName("interval") public String interval;

}

public class Edid {

    @SerializedName("turn_on") public String turnOn;
    @SerializedName("tx_power") public String txPower;
    @SerializedName("interval") public String interval;

}

public class Eurl {

    @SerializedName("turn_on") public String turnOn;
    @SerializedName("tx_power") public String txPower;
    @SerializedName("interval") public String interval;
    @SerializedName("url") public String url;

}

public class Etlm {

    @SerializedName("turn_on") public String turnOn;
    @SerializedName("tx_power") public String txPower;
    @SerializedName("interval") public String interval;

}


来源:https://stackoverflow.com/questions/39892816/retrofit-parsing-json-null-exception-at-response

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!