3

I have defined two classes in Java. Let's call them 'User' and 'Address'

class Address {
    String addressFirstLine;
    String city;
    String pincode;

    // Getters/setters for all attributes
}

class User {
    String firstName;
    String lastName;
    Address address;

    // Getters/setters for all attributes
}

I created an object of class User and serialized it using Gson library.

The JSON String looks something like:

{"firstname":"Zen","lastName":"coder", "Address":{"addressFirstLine":"High st, Point place","city":"Wisconcin","pincode":"4E23C"}}

Now this string is sent to a python application which have the same two class definitions 'User' and 'Address' defined exactly like in Java above.

I have tried deserializing the json to a python object using jsonpickle. I can deserialize simple objects with jsonpickle but not complex objects.

Could anyone suggest a way around this?

dckrooney
  • 3,041
  • 3
  • 22
  • 28
zenCoder
  • 740
  • 4
  • 13
  • 31
  • What does the JSON string look like? – Lee Meador Apr 02 '13 at 14:52
  • just added what the JSON would look like after serialisation using Gson in Java. see edits. – zenCoder Apr 02 '13 at 14:57
  • How about simply writing the custom classemethod `.fromJSON` on both of these classes? – freakish Apr 02 '13 at 14:57
  • I'm not familiar with JSONPickle, but there must be a python library that can do what you require... What does google say? – RudolphEst Apr 02 '13 at 14:58
  • Check out [Colander](http://docs.pylonsproject.org/projects/colander/en/latest/basics.html#deserialization) – Justin Jasmann Apr 02 '13 at 14:58
  • You said "what it would look like". Did you verify that it does look like that? – Lee Meador Apr 02 '13 at 14:58
  • @freakish, that would be a solution if there are very few classes, but I'm dealing with about 40 different classes. Is there a library like Gson that is made for Python? – zenCoder Apr 02 '13 at 14:59
  • @RudolphEst, Unfortunately Google does not have any libraries for Python. jsonpickle and python json libraries proved futile because they cannot deserialise complex objects. – zenCoder Apr 02 '13 at 15:00
  • @LeeMeador, Yes, the JSON string will look like I described above – zenCoder Apr 02 '13 at 15:03
  • If the JSON you're outputting actually looks _exactly_ like the sample, your problem is in the Java component that's producing your JSON. If you feed valid JSON into python's libraries, they work like a champ. – g.d.d.c Apr 02 '13 at 15:08
  • @zenCoder Well, the problem is that unlike Java Python is not strongly typed. Therefore the field (and any other) `Address` can be anything. Now how will you distinguish between types? You will need some more sophisticated structure for that (like Django's ORM) and you will have to send the info about type of a field in JSON. – freakish Apr 02 '13 at 15:17
  • @freakish: "Python is a dynamically and _strongly typed_ programming language..." (emphasis mine). – martineau Apr 02 '13 at 16:07
  • @martineau You obviously are using different definition. But it doesn't really matter imho. It is quite obvious what I'm trying to say. Stop being such a *definition freak*. – freakish Apr 02 '13 at 16:28
  • @zenCoder: In your sample JSON String why is `Address:` not all lowercase and quoted? – martineau Apr 02 '13 at 17:13
  • @martineau: My bad. I updated the JSON string with the double quotes. – zenCoder Apr 02 '13 at 18:15
  • Is there no way to store the object type in the JSON with Gson? So in addition to the above, you'd have an attribute `"type" : "User"`? If you can figure out a way to do that; getting it back in Python is simple: `json_obj = eval(json_string)` and then use `json_obj.type` to create the appropriate object. This is of course assuming that for some reason you can't get the libraries that already do this to work. – Henry Keiter Apr 02 '13 at 18:59
  • @HenryKeiter: What the examples in [this](http://en.wikipedia.org/wiki/GSON) article, GSON doesn't appear to put explicit type information in the JSON strings it creates. – martineau Apr 02 '13 at 19:42

1 Answers1

2

This may be a solution for you using Python built-in JSON library that takes advantage of Python's ability to ingest dictionaries as keyword arguments.

I defined the classes in Python as I would expect based on your outline. In the User class definition, I allow address to be passed as an actual address object, a list (converted from a JSON Array), or a dictionary (converted from a JSON object).

class Address(object):
def __init__(self, addressFirstLine, city, pincode):
    self.addressFirstLine = addressFirstLine
    self.city = city
    self.pincode = pincode


class User(object):
    def __init__(self, firstName, lastName, address):
        self.firstName = firstName
        self.lastName = lastName
        if isinstance(address, Address):
            self.address = address
        elif isinstance(address, list):
            self.address = Address(*address)
        elif isinstance(address, dict):
            self.address = Address(**address)
        else:
            raise TypeError('address must be provided as an Address object,'
            ' list, or dictionary')

I use the built-in Python json library to convert the JSON string you provided to a dictionary, then use that dictionary to create a user object. As you can see below, user.address is an actual Address object (I defined User and Address inside a file called user_address.py, hence the prefix).

>>> import json
>>> user_dict = json.loads('{
    "firstName" : "Zen", "lastName" : "Coder", 
    "address" : {
        "addressFirstLine" : "High st, Point place",
        "city" : "Wisconcin", 
        "pincode" : "4E23C"}
    }')
>>> from user_address import User
>>> user = User(**user_dict)
>>> user
    <user_address.User at 0x1035b4190>
>>> user.firstName
    u'Zen'
>>> user.lastName
     u'coder'
>>> user.address
     <user_address.Address at 0x1035b4710>
>>> user.address.addressFirstLine
    u'High st, Point place'
>>> user.address.city
    u'Wisconcin'
>>> user.address.pincode
    u'4E23C'

This implementation also supports having a list of address arguments as opposed to a dictionary. It also raises a descriptive error if an unsupported type is passed.

>>> user_dict = json.loads('{
    "firstName" : "Zen", "lastName" : "coder", 
    "address" : ["High st, Point place", "Wisconcin", "4E23C"]
    }')
>>> user = User(**user_dict)
>>> user.address
    <user_address.Address at 0x10ced2d10>
>>> user.address.city
    u'Wisconcin'
>>> user_dict = json.loads('{
    "firstName" : "Zen", "lastName" : "coder", 
    "address" : "bad address"
    }')
    TypeError: address must be provided as an Address object, list, or dictionary

This other answer also talks about converting a Python dict to a Python object, with a more abstract approach: Convert Python dict to object

Community
  • 1
  • 1
Jacinda
  • 4,932
  • 3
  • 26
  • 37
  • Thanks a lot for the example. Sounds like the right approach. Before I mark it as the answer, could you tell me if the above approach would work if 'address' were an Array of type Address? – zenCoder Apr 03 '13 at 06:18
  • It won't work as currently written, but I can modify it to do what I think you're asking. Would this be an example of the JSON in this case? {"firstName":"Zen","lastName":"coder", "address":["High st, Point place", "Wisconcin", "4E23C"]} If not, please provide me an example. – Jacinda Apr 03 '13 at 17:28
  • Updated based on what I think you were asking about Arrays. Let me know if this is what you were wondering. – Jacinda Apr 03 '13 at 18:07
  • Actually, I'm warming up to dictionaries. I don't think I need to create objects now. Think it'll work out fine. Thanks everyone! – zenCoder Apr 04 '13 at 19:20