1 | from enum import Enum
|
---|
2 | from typing import Tuple
|
---|
3 |
|
---|
4 |
|
---|
5 | class Id(Enum):
|
---|
6 | '''
|
---|
7 | Id is the way a ClassId is created from a class object.
|
---|
8 | It is recommended to use the default NAME.
|
---|
9 | CLASS may be system dependent and therefore is no good
|
---|
10 | choice for generally usable json.
|
---|
11 | NONE will not cause deserialization issues.
|
---|
12 | '''
|
---|
13 | NONE=0 # don't include ClassId at all.
|
---|
14 | NAME=1 # ClassId=the last part of the full.class.path
|
---|
15 | CLASS=2 # ClassId= full.class.path
|
---|
16 |
|
---|
17 |
|
---|
18 | class As(Enum):
|
---|
19 | '''
|
---|
20 | Identifies how ClassId (see Id) is to be wrapped into json.
|
---|
21 | '''
|
---|
22 | PROPERTY=0 # add 'type':ClassId attribute to the object dict
|
---|
23 | WRAPPER_OBJECT=1 # wrap object in dict, with ClassId as key
|
---|
24 | WRAPPER_ARRAY=2 # ...
|
---|
25 |
|
---|
26 |
|
---|
27 |
|
---|
28 | def JsonTypeInfo(use:Id, include:As):
|
---|
29 | '''
|
---|
30 | rudimentary component,
|
---|
31 | following packson structure but limited actual support in ObjecMapper.
|
---|
32 | puts a tuple (use, include) in the field __jsontypeinfo__ of the annotated class.
|
---|
33 | '''
|
---|
34 |
|
---|
35 |
|
---|
36 | def doAnnotate(annotatedclass):
|
---|
37 | setattr(annotatedclass,'__jsontypeinfo__', (use, include))
|
---|
38 | return annotatedclass
|
---|
39 |
|
---|
40 |
|
---|
41 | '''
|
---|
42 | A bit complex mechanism that just sets
|
---|
43 | attribute __jsonsubtypes__ of the annotated class to the tuple
|
---|
44 | (id, as).
|
---|
45 | .
|
---|
46 | @param subclassnames a list of full class names of subclasses.
|
---|
47 | '''
|
---|
48 | if not isinstance(use, Id):
|
---|
49 | raise ValueError("use must be JsonTypeInfo.Id")
|
---|
50 | if not isinstance(include, As):
|
---|
51 | raise ValueError("include must be JsonTypeInfo.As")
|
---|
52 | return doAnnotate
|
---|
53 |
|
---|
54 |
|
---|
55 | ##### support functions.
|
---|
56 | # these are static functions because they handle class objects directly
|
---|
57 |
|
---|
58 |
|
---|
59 | def getClassId(clas) -> str:
|
---|
60 | '''
|
---|
61 | @param clas the clas to get ID for
|
---|
62 | @return the classId for the given class and use method.
|
---|
63 | The classId is a string tag referring to a class.
|
---|
64 | '''
|
---|
65 | (use, _include)=getTypeWrappingInfo(clas)
|
---|
66 | if use==Id.NAME:
|
---|
67 | return getattr(clas,'__name__')
|
---|
68 | if use==Id.CLASS:
|
---|
69 | return getattr(clas,'__module__')+"."+getattr(clas,'__name__')
|
---|
70 | raise ValueError("Not implemented type info "+str(use))
|
---|
71 |
|
---|
72 | def getTypeWrappingInfo( clas )->Tuple[Id, As]:
|
---|
73 | '''
|
---|
74 | @param clas: a dict that should include way class information is wrapped into the dict
|
---|
75 | @param defaultval: a Tuple[Id, As] containing defaul tif clas does not contain setting.
|
---|
76 | @return (use,include) tuple that indicates how type
|
---|
77 | information is to be wrapped into the json object.
|
---|
78 | Or defaultval if the class is not annotated.
|
---|
79 | '''
|
---|
80 | if hasattr(clas, '__jsontypeinfo__'):
|
---|
81 | return getattr(clas, '__jsontypeinfo__')
|
---|
82 | return None
|
---|
83 |
|
---|
84 |
|
---|