Reputation: 53
I'm having trouble reading a JSON file into a POJO. Let me give you a snippet of what my JSON file entails:
{
"Speidy": {
"factionId": "2",
"role": "ADMIN",
"title": "",
"power": 9.692296666666667,
"powerBoost": 0.0,
"lastPowerUpdateTime": 1337023306922,
"lastLoginTime": 1337023306922,
"chatMode": "PUBLIC"
},
"ShadowSlayer272": {
"factionId": "2",
"role": "NORMAL",
"title": "",
"power": 0.8673466666666667,
"powerBoost": 0.0,
"lastPowerUpdateTime": 1336945426926,
"lastLoginTime": 1336945426926,
"chatMode": "PUBLIC"
},
My issue is the first 'node' is completely random, i.e how can I make a POJO file for it if it's different each time?
My POJO file for the sub-data is like this:
public class Node {
private int factionId = 0;
private String role = "";
private String title = "";
private double power = 0.0;
private double powerBoost = 0.0;
private int lastPowerUpdateTime = 0;
private int lastLoginTime = 0;
private String chatMode = "";
}
And then my other POJO file is this:
public class Container {
private List<Node> nodes; //What should nodes be for GSON to get each random one?
public List<Node> getNodes() {
return nodes;
}
}
I appreciate all help, thank you.
UPDATE
I tried changing the List
to a Map
as such:
public class Container {
private Map<String,Node> nodes;
public Map<String,Node> getNodes() {
return nodes;
}
While keeping the node file the same. The string would then be the property name i.e Speidy
or ShadowSlayer272
. However, gson never does anything with nodes, and when I try and to getNodes()
, it returns a null
object.
Thanks for the help.
Upvotes: 1
Views: 1328
Reputation: 20961
If you do have control the format of the JSON, I suggest the overall list structure that jmort253 suggests in his answer, i.e. [{"name":"Speidy", ... },{"name":"ShadowSlayer272", ... }]
.
If you have no control over the generated JSON, here's two ways to map a JSON snippet like the one in your question {"Speidy":{ ... },"ShadowSlayer272":{ ... }}
with Gson:
Without your Container
class and a little bit of TypeToken
voodoo:
// Ask Gson to deserialize the JSON snippet into a Map<String, Node>.
Type type = new TypeToken<Map<String, Node>>() {}.getType();
Map<String, Node> nodes = gson.fromJson(json, type);
With your Container
class and a custom JsonDeserializer
:
class ContainerDeserializer implements JsonDeserializer<Container> {
public Container deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
List<Node> nodes = new ArrayList<Node>();
JsonObject players = json.getAsJsonObject();
for (Entry<String, JsonElement> player : players.entrySet()) {
String playerName = player.getKey();
JsonElement playerData = player.getValue();
// Use Gson to deserialize all fields except
// for the name into a Node instance ...
Node node = context.deserialize(playerData, Node.class);
node.name = playerName; // ... then set the name.
nodes.add(node);
}
return new Container(nodes);
}
}
This assumes a constructor like Container(List<Node>)
and allows Container
instances to be immutable which is usually a Good Thing.
Register and use the custom serializer like this:
GsonBuilder builder = new GsonBuilder();
// Tell Gson to use the custom ContainerDeserializer whenever
// it's asked for a Container instance.
builder.registerTypeAdapter(Container.class, new ContainerDeserializer());
Gson gson = builder.create();
// Ask Gson to create Container instance from your JSON snippet.
Container container = gson.fromJson(json, Container.class);
Upvotes: 1
Reputation: 34038
You're listing what appears to be a name, which you possibly meant to represent a value, as a property name for an object. Instead, include the name inside the JSON string and assign it a property name that will actually appear as a private variable (with getters and setters) in your Java Node class.
With this in place, you should then be able to deserialize your JSON back into an object. Also, since on the server-side you're representing the Node collection as a List, I converted the JSON to an array that contains two objects. In JavaScript, you'd access them as node[0].name
and node[1].name
, which would equate to nodes.get(0).getName()
on the server-side:
[
{
"name" : "Speidy",
"factionId": "2",
"role": "ADMIN",
"title": "",
"power": 9.692296666666667,
"powerBoost": 0.0,
"lastPowerUpdateTime": 1337023306922,
"lastLoginTime": 1337023306922,
"chatMode": "PUBLIC"
},
{
"name" : "ShadowSlayer272",
"factionId": "2",
"role": "NORMAL",
"title": "",
"power": 0.8673466666666667,
"powerBoost": 0.0,
"lastPowerUpdateTime": 1336945426926,
"lastLoginTime": 1336945426926,
"chatMode": "PUBLIC"
}
]
public class Node {
private String name = "";
private int factionId = 0;
private String role = "";
private String title = "";
private double power = 0.0;
private double powerBoost = 0.0;
private int lastPowerUpdateTime = 0;
private int lastLoginTime = 0;
private String chatMode = "";
}
With that said, if you really do need to use the name as a property name, then consider deserializing the JSON to a HashMap instead of a List. Lists generally map to JSON arrays, whereas Maps generally are better suited towards representing several JSON objects inside a parent object.
Upvotes: 2