32

I'm trying to fill my JSONObject like this:

JSONObject json = new JSONObject();
json.put("Command", "CreateNewUser");
json.put("User", user);

user is instance of basic class that contains fields like "FirstName", "LastName" etc.

Looks like I'm doing it wrong, because I get JSON like this:

{
    "Command":"CreateNewUser",
    "User":"my.package.name.classes.User@2686a150"
}

instead of "tree".

What is wrong with my code?

Kamil
  • 13,363
  • 24
  • 88
  • 183

5 Answers5

58

Since you use JSONObject to represent non-primitive types, any instance passed to JSONObject.put(Object, Object) will generate nested items (or trees).

JSONObject main = new JSONObject();
main.put("Command", "CreateNewUser");
JSONObject user = new JSONObject();
user.put("FirstName", "John");
user.put("LastName", "Reese");
main.put("User", user);
{
    "User": {
        "FirstName": "John",
        "LastName": "Reese"
    },
    "Command": "CreateNewUser"
}
spongebob
  • 8,370
  • 15
  • 50
  • 83
  • Why is "User" before "Command" even though main.put("Command", "CreateNewUser"); comes before main.put("User", user); – most venerable sir Mar 28 '18 at 14:01
  • 2
    @mostvenerablesir Because, [per JSON spec](https://stackoverflow.com/a/4920304/3453226), an object is an _unordered_ set of name/value pairs. Therefore, the order of elements may be rearranged as needed. – spongebob Mar 29 '18 at 10:24
  • ok you just write it in the reverse order to what the code would generate? – most venerable sir Mar 30 '18 at 01:34
  • 1
    @mostvenerablesir No, that is the result of calling [`main.toString(4)`](https://developer.android.com/reference/org/json/JSONObject.html#toString(int)). The library itself has rearranged the order of elements for performance reasons, since it is not required to preserve their insertion order. – spongebob Mar 30 '18 at 09:08
10

This will do what you want !

JSONObject json = new JSONObject();
json.put("Command", "CreateNewUser");
json.put("User", new JSONObject(user));
Hrant Vardanyan
  • 265
  • 1
  • 4
  • 11
5

The framework you are using does not know how to convert your User object to a Map, that is used internally as JSON representation and so it is using standard 'toString' method that you have not overriden.

Just export all properties (for example write method 'Map toMap()' on your User type ) of your User to a Map (all values must be standard JDK types) and put that map in your json object:

json.put("User", user.toMap())

It will do the thing.

Rafal G.
  • 4,252
  • 1
  • 25
  • 41
1

From http://developer.android.com/reference/org/json/JSONObject.html#put

 public JSONObject put (String name, Object value)

Parameters value a JSONObject, JSONArray, String, Boolean, Integer, Long, Double, NULL, or null. May not be NaNs or infinities.

Though your user is subclass of Object, it is not the type that the put method expects.

The android SDK's implementation of JSONObject seems lacking a put(java.lang.String key, java.util.Map value) method (from the same link above). You may need to add a method toMap() in your user class to convert it into a HashMap. Then finally use json.put("user", new JSONObject(user.toMap()));

user2829759
  • 3,372
  • 2
  • 29
  • 53
0

You can solve it using fasterxml ObjectMapper.

ObjectMapper o = new ObjectMapper();
String userJsonString = o.readValueAsString(user);

JSONObject jsonObj = new JSONObject();
jsonObj.put("Command", "CreateNewUser");
jsonObj.put("User", new JSONObject(userJsonString));

You will get following output:

{
    "User": {
        "FirstName": "John",
        "LastName": "Reese"
    },
    "Command": "CreateNewUser"
}

Ref: https://github.com/FasterXML/jackson-databind/

Kevindra
  • 1,682
  • 3
  • 24
  • 45