Gson.toJson() misordering items

谁都会走 提交于 2019-12-11 11:12:09

问题


I have this output JSON:

{
  "id": 42950262095,
  "name": "lol",
  "players": [
    {
      "avatar": {
        "userId": 25771876384,
        "userName": "yhht",
        "role": "Leader",
        "level": 40,
        "league": 0,
        "trophies": 1011,
        "donatedTroops": 0,
        "receivedTroops": 0
      }
    },
    {
      "avatar": {
        "userId": 146035414262,
        "userName": "ari",
        "role": "New Member",
        "level": 8,
        "league": 0,
        "trophies": 428,
        "donatedTroops": 0,
        "receivedTroops": 0
      }
    },
    {
      "avatar": {
        "userId": 300659467521,
        "userName": "cp 221",
        "role": "New Member",
        "level": 6,
        "league": 0,
        "trophies": 97,
        "donatedTroops": 0,
        "receivedTroops": 0
      }
    }
  ],
  "badge": 13000049,
  "status": "Anyone Can Join",
  "playerCount": 3,
  "score": 767,
  "requiredTrophies": 0,
  "warsWon": 0,
  "warsLost": 0,
  "warsTied": 0,
  "warFrequency": 0,
  "exp": 0,
  "level": 1,
  "description": "??lol????"
}

But the problem is the players array comes too early and part of the initial details are left out.

This is my code:

public void parseAvatar() throws IOException, JSONException{

        Game game = new Game();

        game.setId(is.readLong());
        game.setName(is.readString());
        game.setBadge(is.readInt());
        game.setStatus(status(is.readInt()));
        game.setPlayerCount(is.readInt());
        game.setScore(is.readInt());
        game.setRequiredTrophies(is.readInt());
        game.setWarsWon(is.readInt());
        game.setWarsLost(is.readInt());
        game.setWarsTied(is.readInt());
        is.readInt();
        game.setWarFrequency(is.readInt());
        is.readInt();
        game.setExp(is.readInt());
        game.setLevel(is.readInt());
        game.setDescription(is.readString());
        is.readInt();
        boolean a = is.readBoolean();

        if(a){
            is.readInt();
            is.readInt();
        }

        int memCount = is.readInt();
        /// Members!!

        int i = 0;
        while(i < memCount){
            PlayerAvatar avatar = new PlayerAvatar();
            avatar.setUserId(is.readLong());
            avatar.setUserName(is.readString());
            avatar.setRole(role(is.readInt()));
            avatar.setLevel(is.readInt());
            avatar.setLeague(is.readInt());
            avatar.setTrophies(is.readInt());
            avatar.setDonatedTroops(is.readInt());
            avatar.setReceivedTroops(is.readInt());
            is.readInt();
            is.readInt();
            is.readLong();
            is.readByte();
            is.readByte();
            is.readLong();

            GamePlayer player = new GamePlayer();
            player.setAvatar(avatar);
            game.addPlayers(player);
            i++;
        }


        json = new Gson().toJson(game);
        System.out.println();
    }


    private String role(int role) {
        String memberRole = "";

        if(role == 1){
            memberRole = "New Member";
        }   

        if(role == 2){
            memberRole = "Leader";
        }   

        if(role == 3){
            memberRole = "Elder";
        }   

        if(role == 4){
            memberRole = "Co Leader";
        }   

        return memberRole;
    }

    private String status(int statusint) {
        String type = null;
        if(statusint == 1){
            type = "Anyone Can Join";
        }
        if(statusint == 2){
            type = "Invite Only";
        }
        if(statusint == 3){
            type = "Closed";
        }
        return type;
    }

You can find details for the Game, PlayerAvatar and GamePlayer class in this post: https://stackoverflow.com/a/33048622

Does anyone have any idea on how I can get this ordered properly?


回答1:


Gson create json string according to your object's fields declaration order (Even if not guaranteed because "reflection ordering may change in JDK 9" in the future:), it works.)

Be sure that your JDK is min 6. Gson is min 2.2.4 version.

private Long id;
private String name;
private List<Player> players;

prints as json string: first id, name then players.

{
  "id": 171799578198,
  "name": "Forum Striking",
  "players": [
    {
      "avatar": {
        "userId": 21393,
        "currentHomeId": 21393,
        "clanId": 171799578198
      }
    },
    {
      "avatar": {
        "userId": 64425223942,
        "currentHomeId": 64425223942,
        "clanId": 171799578198
      }
    }
  ]
}

private Long id;
private List<Player> players;
private String name;

prints as json string: id, players and name at the end.

{
  "id": 171799578198,
  "players": [
    {
      "avatar": {
        "userId": 21393,
        "currentHomeId": 21393,
        "clanId": 171799578198
      }
    },
    {
      "avatar": {
        "userId": 64425223942,
        "currentHomeId": 64425223942,
        "clanId": 171799578198
      }
    }
  ],
  "name": "Forum Striking"
}

So you should declare player list at the end of the your game object.




回答2:


JSON objects are by definition unordered - you should not be relying on the order of properties. So what gson is doing is perfectly fine.

If for some reason you have no choice but to rely on the ordering, there are some solutions in this question: How to keep fields sequence in Gson serialization (e.g. use jackson instead of gson and use @JsonPropertyOrder, or implement a custom serializer).

With current gson and JDK implementations, reordering the members in your class will produce output in the corresponding order, however this is a very brittle solution. For example

  • The JDK doesn't guarantee the order in which fields are read through reflection, and it could change in future (it has changed in the past), which would break your code. (This is actually the least likely issue, but it's possible). In fact the JDK 8 documentation explicitly says

    The elements in the returned array are not sorted and are not in any particular order

  • Even if the JDK's ordering doesn't change, gson doesn't guarantee that it will return them in the same order. It currently does return them in the same order, but if for some reason the internals of gson changed e.g. to use an intermediate HashMap, the order would change and your code would break.
  • If someone else in the future is maintaining your class, it would be very surprising for them to find that just reordering the fields in the class would break the code - the ordering of fields in a java class should not change functionality.

If you're writing code only for your own amusement, or to use once to convert some data, it might be no big deal, but if you're writing code that others (or even Future You) will need to maintain, I strongly recommend you write code that doesn't rely on layers of assumptions, and/or on constant testing to make sure multiple undocumented behaviours haven't changed.

Spending a few minutes now incorporating code to actually guarantee the ordering of your fields could save hours or days of debugging down the line. This happens all the time in real life.



来源:https://stackoverflow.com/questions/33051729/gson-tojson-misordering-items

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