Reputation: 71
I am trying to encode/decode nested objects and I have the list of nested objects as a string instead of JSON objects.
class A:
def __init__ (self, n, a):
self.n = n
self.a = a
class B:
def __init__ (self, b, listOfA):
self.b = b
self.listOfA = []
for a in listOfA:
self.listOfA.append(a)
class AEncoder:
def default (self, obj):
if isinstance (obj, A):
return {
'n' : obj.n
'a' : obj.a
}
return json.JSONEncoder.default(self, obj)
class BEncoder:
def default (self, obj):
if isinstance (obj, B):
return {
'b' : obj.n
'listOfA' : json.dumps(obj.listOfA, cls=AEncoder)
}
return json.JSONEncoder.default(self, obj)
listOfA = [A('n1', 'a1'), A('n2', 'a2')]
tmpB = B('b', listOfA)
For object A it is working correctly as it is fairly straight forward. The output for B I get is something like this:
{
"b" : "b"
"listOfA" : "[{\"n\" : \"n1\", \"a\" : \"a1\"}, {\"n\" : \"n2\", \"a\" : \"a2\"}]"
}
Any ideas where I am wrong? The output should be like this:
{
"b" : "b"
"listOfA" : [{"n" : "n1", "a" : "a1"}, {"n" : "n2", "a" : "a2"}]
}
Upvotes: 3
Views: 3640
Reputation: 2503
You had a few typos in your code, missing commas in dictionaries and you refer to obj.n when you meant obj.b in BEncoder.
Aside from that, the problem is that you are using json.dumps() in the BEncoder. This method is returning a properly-formatted json string. The BEncoder then sees this string and thinks you want the value of listOfA to be a string, which should then be encoded properly for json, thus the character escaping you're seeing.
Here is a solution, that instead of returning a string, returns a "serializable object" (e.g., a list, dict, etc.), as needed by the encoder. It is building a list (which is serializable) out of the dictionaries (serializable) returned by AEncoder().default().
import json
from json import JSONEncoder
class A:
def __init__ (self, n, a):
self.n = n
self.a = a
class B:
def __init__ (self, b, listOfA):
self.b = b
self.listOfA = []
for a in listOfA:
self.listOfA.append(a)
class AEncoder(JSONEncoder):
def default (self, obj):
if isinstance (obj, A):
return { 'n' : obj.n, 'a' : obj.a }
return json.JSONEncoder.default(self, obj)
class BEncoder(JSONEncoder):
def default (self, obj):
if isinstance (obj, B):
a = AEncoder()
return { 'b' : obj.b, 'listOfA' : [a.default(x) for x in obj.listOfA] }
return json.JSONEncoder.default(self, obj)
listOfA = [A('n1', 'a1'), A('n2', 'a2')]
tmpB = B('b', listOfA)
print(json.dumps(tmpB, cls=BEncoder))
The output:
{"b": "b", "listOfA": [{"a": "a1", "n": "n1"}, {"a": "a2", "n": "n2"}]}
Upvotes: 6