简体   繁体   中英

What is the alternative of Jackson in python?

I am using Jackson parser for parsing for Java object to JSON . I am forcefully adding JSON keys for some java objects, using the following code.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonSubTypes({ @JsonSubTypes.Type(value = A.class, name = "a"),
        @JsonSubTypes.Type(value = F.class, name = "f") })

I am having same set classes in Python also. I would like to do the same thing in python. But not sure about what are the alternatives for this Jackson annotation available in python.

My requirement is that I have to send a POST request to a REST API. I need to serialize the java object into JSON. But as my class structure is a little bit different I don't have all the JSON keys mentioned handy in java classes. To solve the issue what I am doing is that I am adding 'a' key in JSON when it finds 'A' object is passed from java. It is doing the same thing for 'F' object. So, I have achieved the solution the way I mentioned above. I want to achieve the same thing in Python.

Is there some JSON parser available what does the same thing as mentioned above, or I have to follow some different approach for that?

I would strongly recommend the pydantic library, which also provides the possibility to add validations of the data.

It is very easy and straightforward to use, also if you only use it for json marshalling/unmarshalling.

https://pypi.org/project/pydantic/

import json
from datetime import datetime

from pydantic import BaseModel


class MyInnerClass(BaseModel):
    timestamp: datetime
    some_string: str


class MyOuterClass(BaseModel):
    inner_instance: MyInnerClass
    other_string: str


# Class to json
test_class = MyOuterClass(inner_instance=MyInnerClass(timestamp=datetime(2022, 6, 22), some_string="some"),
                          other_string="other")

json_string = test_class.json()

# Json to Class

input_string = '{"inner_instance": {"timestamp": "2022-06-22T00:00:00", "some_string": "some"}, "other_string": "other"}'
loaded_class = MyOuterClass(**json.loads(input_string))

attrs + cattrs is very close for the task.

copy one cattr example here,

>>> import attr, cattr
>>>
>>> @attr.s(slots=True, frozen=True)  # It works with normal classes too.
... class C:
...     a = attr.ib()
...     b = attr.ib()
...
>>> instance = C(1, 'a')
>>> cattr.unstructure(instance)
{'a': 1, 'b': 'a'}
>>> cattr.structure({'a': 1, 'b': 'a'}, C)
C(a=1, b='a')

but it's not as capable as Jackson, i've not yet been able to find a solution to map attribute between serialized json and deserialized python object.

I have the same problem and could not find anything suitable. So I wrote pyson

https://tracinsy.ewi.tudelft.nl/pubtrac/Utilities/wiki/pyson

It's still under development and I will add new features along the way. It's not ment to be a complete substitute for jackson as jackson is huge. I just implement what I need, in jackson style where possible.

I think the most similar option you will get in python ecosystem will be jsonpickle

although it's not as complete as complete Jackson. python engineers and users chose a different respectable perspective and that is using schema-less approaches to problems so typing oriented serialization libraries like Jackson doesn't have a strong equivalent in Python.

You can use Jsonic library.

Jsonic is a lightweight utility for serializing/deserializing python objects to/from JSON.

Jsonic allows serializing/deserializing to/from specific Class instances.

It supports many of the functionalities Jackson supports in Java.

Example:

from jsonic import serialize, deserialize

class User(Serializable):
    def __init__(self, user_id: str, birth_time: datetime):
        super().__init__()
        self.user_id = user_id
        self.birth_time = birth_time

user = User('id1', datetime(2020,10,11))      
obj = serialize(user) # {'user_id': 'id1', 'birth_time': {'datetime': '2020-10-11 00:00:00', '_serialized_type': 'datetime'}, '_serialized_type': 'User'}

# Here the magic happens
new_user : User = deserialize(obj) # new_user is a new instance of user with same attributes

Jsonic has some nifty features:

  1. You can serialize objects of types that are not extending Serializable. 2. This can come handy when you need to serialize objects of third party library classes.
  2. Support for custom serializers and deserializers
  3. Serializing into JSON string or python dict
  4. Transient class attributes
  5. Supports both serialization of private fields or leave them out of the serialization process.

Here you can find some more advanced example:

from jsonic import Serializable, register_jsonic_type, serialize, deserialize

class UserCredentials:
"""
Represents class from some other module, which does not extend Serializable
We can register it using register_serializable_type function
"""

def __init__(self, token: str, exp: datetime):
    self.token = token
    self.expiration_time = exp
    self.calculatedAttr = random.uniform(0, 1)

# Register UserCredentials which represents class from another module that does not implement Serializable
# exp __init__ parameter is mapped to expiration_time instace attribute
register_jsonic_type(UserCredentials, init_parameters_mapping={'exp': 'expiration_time'})


class User(Serializable):
    transient_attributes = ['user_calculated_attr'] # user_calculated_attr won't be serialized and deserialzied
    init_parameters_mapping = {'id': 'user_id'} # id __init__ parameter is mapped to user_id instace attribute

    def __init__(self, user_id: str, birth_time: datetime, user_credentials: UserCredentials, *args):
        super().__init__()
        self.user_id = user_id
        self.birth_time = birth_time
        self.user_credentials = user_credentials
        self.user_calculated_attr = 'user_calculated_attr'
    
user = User(user_id='user_1', birth_time=datetime(1995, 7, 5, 0),
     user_credentials=UserCredentials(token='token', exp=datetime(2020, 11, 1, 0)))
 


# Here the magic happens
user_json_obj = serialize(user, string_output=True)
new_user = deserialize(user_json_obj, string_input=True, expected_type=User)

Full disclosure: I'm the creator of Jsonic, i recommend you read the Jsonic GitHub repository README to see if it fits your needs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM