1
+ package moe .banana .jsonapi2 ;
2
+
3
+ import com .squareup .moshi .JsonAdapter ;
4
+ import com .squareup .moshi .Moshi ;
5
+ import com .squareup .moshi .Types ;
6
+
7
+ import java .io .IOException ;
8
+ import java .lang .annotation .Annotation ;
9
+ import java .lang .reflect .Array ;
10
+ import java .lang .reflect .ParameterizedType ;
11
+ import java .lang .reflect .Type ;
12
+ import java .util .ArrayList ;
13
+ import java .util .List ;
14
+
15
+ import moe .banana .jsonapi2 .ArrayDocument ;
16
+ import moe .banana .jsonapi2 .Document ;
17
+ import moe .banana .jsonapi2 .ObjectDocument ;
18
+ import moe .banana .jsonapi2 .Resource ;
19
+ import moe .banana .jsonapi2 .ResourceIdentifier ;
20
+ import okhttp3 .MediaType ;
21
+ import okhttp3 .RequestBody ;
22
+ import okhttp3 .ResponseBody ;
23
+ import okio .Buffer ;
24
+ import retrofit2 .Converter ;
25
+ import retrofit2 .Retrofit ;
26
+
27
+ @ SuppressWarnings ("unchecked" )
28
+ public final class JsonApiConverterFactory extends Converter .Factory {
29
+
30
+ public static JsonApiConverterFactory create () {
31
+ return create (new Moshi .Builder ().build ());
32
+ }
33
+
34
+ public static JsonApiConverterFactory create (Moshi moshi ) {
35
+ return new JsonApiConverterFactory (moshi , false );
36
+ }
37
+
38
+ private final Moshi moshi ;
39
+ private final boolean lenient ;
40
+
41
+ private JsonApiConverterFactory (Moshi moshi , boolean lenient ) {
42
+ if (moshi == null ) throw new NullPointerException ("moshi == null" );
43
+ this .moshi = moshi ;
44
+ this .lenient = lenient ;
45
+ }
46
+
47
+ public JsonApiConverterFactory asLenient () {
48
+ return new JsonApiConverterFactory (moshi , true );
49
+ }
50
+
51
+ private JsonAdapter <?> getAdapterFromType (Type type ) {
52
+ Class <?> rawType = Types .getRawType (type );
53
+ JsonAdapter <?> adapter ;
54
+ if (rawType .isArray () && ResourceIdentifier .class .isAssignableFrom (rawType .getComponentType ())) {
55
+ adapter = moshi .adapter (Types .newParameterizedType (Document .class , rawType .getComponentType ()));
56
+ } else if (List .class .isAssignableFrom (rawType ) && type instanceof ParameterizedType ) {
57
+ Type typeParameter = ((ParameterizedType ) type ).getActualTypeArguments ()[0 ];
58
+ if (typeParameter instanceof Class <?> && ResourceIdentifier .class .isAssignableFrom ((Class <?>) typeParameter )) {
59
+ adapter = moshi .adapter (Types .newParameterizedType (Document .class , typeParameter ));
60
+ } else {
61
+ return null ;
62
+ }
63
+ } else if (ResourceIdentifier .class .isAssignableFrom (rawType )) {
64
+ adapter = moshi .adapter (Types .newParameterizedType (Document .class , rawType ));
65
+ } else if (Document .class .isAssignableFrom (rawType )) {
66
+ adapter = moshi .adapter (Types .newParameterizedType (Document .class , Resource .class ));
67
+ } else {
68
+ return null ;
69
+ }
70
+ return adapter ;
71
+ }
72
+
73
+ @ Override
74
+ public Converter <ResponseBody , ?> responseBodyConverter (Type type , Annotation [] annotations , Retrofit retrofit ) {
75
+ JsonAdapter <?> adapter = getAdapterFromType (type );
76
+ if (adapter == null ) {
77
+ return null ;
78
+ }
79
+ if (lenient ) {
80
+ adapter = adapter .lenient ();
81
+ }
82
+ return new MoshiResponseBodyConverter <>((JsonAdapter <Document >) adapter , type );
83
+ }
84
+
85
+ @ Override
86
+ public Converter <?, RequestBody > requestBodyConverter (Type type , Annotation [] parameterAnnotations , Annotation [] methodAnnotations , Retrofit retrofit ) {
87
+ JsonAdapter <?> adapter = getAdapterFromType (type );
88
+ if (adapter == null ) {
89
+ return null ;
90
+ }
91
+ if (lenient ) {
92
+ adapter = adapter .lenient ();
93
+ }
94
+ return new MoshiRequestBodyConverter <>((JsonAdapter <Document >) adapter , type );
95
+ }
96
+
97
+ private static final MediaType MEDIA_TYPE = MediaType .parse ("application/json; charset=UTF-8" );
98
+
99
+ private static class MoshiResponseBodyConverter <R > implements Converter <ResponseBody , R > {
100
+ private final JsonAdapter <Document > adapter ;
101
+ private final Class <R > rawType ;
102
+
103
+ MoshiResponseBodyConverter (JsonAdapter <Document > adapter , Type type ) {
104
+ this .adapter = adapter ;
105
+ this .rawType = (Class <R >) Types .getRawType (type );
106
+ }
107
+
108
+ @ Override
109
+ public R convert (ResponseBody value ) throws IOException {
110
+ try {
111
+ Document document = adapter .fromJson (value .source ());
112
+ if (Document .class .isAssignableFrom (rawType )) {
113
+ return (R ) document ;
114
+ } else if (List .class .isAssignableFrom (rawType )) {
115
+ ArrayDocument arrayDocument = document .asArrayDocument ();
116
+ List a ;
117
+ if (rawType .isAssignableFrom (ArrayList .class )) {
118
+ a = new ArrayList ();
119
+ } else {
120
+ a = (List ) rawType .newInstance ();
121
+ }
122
+ a .addAll (arrayDocument );
123
+ return (R ) a ;
124
+ } else if (rawType .isArray ()) {
125
+ ArrayDocument <?> arrayDocument = document .asArrayDocument ();
126
+ Object a = Array .newInstance (rawType .getComponentType (), arrayDocument .size ());
127
+ for (int i = 0 ; i != Array .getLength (a ); i ++) {
128
+ Array .set (a , i , arrayDocument .get (i ));
129
+ }
130
+ return (R ) a ;
131
+ } else {
132
+ return (R ) document .asObjectDocument ().get ();
133
+ }
134
+ } catch (InstantiationException e ) {
135
+ throw new RuntimeException ("Cannot find default constructor of [" + rawType .getCanonicalName () + "]." , e );
136
+ } catch (IllegalAccessException e ) {
137
+ throw new RuntimeException ("Cannot access default constructor of [" + rawType .getCanonicalName () + "]." , e );
138
+ } finally {
139
+ value .close ();
140
+ }
141
+ }
142
+ }
143
+
144
+ private static class MoshiRequestBodyConverter <T > implements Converter <T , RequestBody > {
145
+
146
+ private final JsonAdapter <Document > adapter ;
147
+ private final Class <T > rawType ;
148
+
149
+ MoshiRequestBodyConverter (JsonAdapter <Document > adapter , Type type ) {
150
+ this .adapter = adapter ;
151
+ this .rawType = (Class <T >) Types .getRawType (type );
152
+ }
153
+
154
+ @ Override
155
+ public RequestBody convert (T value ) throws IOException {
156
+ Document document ;
157
+ if (Document .class .isAssignableFrom (rawType )) {
158
+ document = (Document ) value ;
159
+ } else if (List .class .isAssignableFrom (rawType )) {
160
+ ArrayDocument arrayDocument = new ArrayDocument ();
161
+ List a = ((List ) value );
162
+ if (!a .isEmpty () && a .get (0 ) != null && ((ResourceIdentifier ) a .get (0 )).getContext () != null ) {
163
+ arrayDocument = ((ResourceIdentifier ) a .get (0 )).getContext ().asArrayDocument ();
164
+ }
165
+ arrayDocument .addAll (a );
166
+ document = arrayDocument ;
167
+ } else if (rawType .isArray ()) {
168
+ ArrayDocument arrayDocument = new ArrayDocument ();
169
+ if (Array .getLength (value ) > 0 && ((ResourceIdentifier ) Array .get (value , 0 )).getContext () != null ) {
170
+ arrayDocument = ((ResourceIdentifier ) Array .get (value , 0 )).getContext ().asArrayDocument ();
171
+ }
172
+ for (int i = 0 ; i != Array .getLength (value ); i ++) {
173
+ arrayDocument .add ((ResourceIdentifier ) Array .get (value , i ));
174
+ }
175
+ document = arrayDocument ;
176
+ } else {
177
+ ResourceIdentifier data = ((ResourceIdentifier ) value );
178
+ ObjectDocument objectDocument = new ObjectDocument ();
179
+ if (data .getDocument () != null ) {
180
+ objectDocument = data .getDocument ().asObjectDocument ();
181
+ }
182
+ objectDocument .set (data );
183
+ document = objectDocument ;
184
+ }
185
+ Buffer buffer = new Buffer ();
186
+ adapter .toJson (buffer , document );
187
+ return RequestBody .create (MEDIA_TYPE , buffer .readByteString ());
188
+ }
189
+ }
190
+
191
+ }
0 commit comments