21
21
import java .util .List ;
22
22
import java .util .Map ;
23
23
24
+ import com .fasterxml .jackson .core .JsonFactory ;
25
+ import com .fasterxml .jackson .core .JsonParser ;
24
26
import com .fasterxml .jackson .core .JsonProcessingException ;
25
27
import com .fasterxml .jackson .databind .JavaType ;
26
28
import com .fasterxml .jackson .databind .ObjectMapper ;
27
29
import com .fasterxml .jackson .databind .ObjectReader ;
28
30
import com .fasterxml .jackson .databind .exc .InvalidDefinitionException ;
31
+ import com .fasterxml .jackson .databind .util .TokenBuffer ;
32
+ import org .eclipse .jetty .io .RuntimeIOException ;
29
33
import org .reactivestreams .Publisher ;
30
34
import reactor .core .publisher .Flux ;
31
35
import reactor .core .publisher .Mono ;
35
39
import org .springframework .core .codec .CodecException ;
36
40
import org .springframework .core .codec .DecodingException ;
37
41
import org .springframework .core .io .buffer .DataBuffer ;
38
- import org .springframework .core .io .buffer .DataBufferUtils ;
39
42
import org .springframework .http .codec .HttpMessageDecoder ;
40
43
import org .springframework .http .converter .json .Jackson2ObjectMapperBuilder ;
41
44
import org .springframework .http .server .reactive .ServerHttpRequest ;
54
57
*/
55
58
public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpMessageDecoder <Object > {
56
59
57
- private final JsonObjectDecoder fluxDecoder = new JsonObjectDecoder (true );
58
-
59
- private final JsonObjectDecoder monoDecoder = new JsonObjectDecoder (false );
60
-
61
-
62
60
public Jackson2JsonDecoder () {
63
61
super (Jackson2ObjectMapperBuilder .json ().build ());
64
62
}
@@ -67,7 +65,6 @@ public Jackson2JsonDecoder(ObjectMapper mapper, MimeType... mimeTypes) {
67
65
super (mapper , mimeTypes );
68
66
}
69
67
70
-
71
68
@ Override
72
69
public boolean canDecode (ResolvableType elementType , @ Nullable MimeType mimeType ) {
73
70
JavaType javaType = objectMapper ().getTypeFactory ().constructType (elementType .getType ());
@@ -76,7 +73,6 @@ public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType
76
73
objectMapper ().canDeserialize (javaType ) && supportsMimeType (mimeType ));
77
74
}
78
75
79
-
80
76
@ Override
81
77
public List <MimeType > getDecodableMimeTypes () {
82
78
return JSON_MIME_TYPES ;
@@ -86,20 +82,27 @@ public List<MimeType> getDecodableMimeTypes() {
86
82
public Flux <Object > decode (Publisher <DataBuffer > input , ResolvableType elementType ,
87
83
@ Nullable MimeType mimeType , @ Nullable Map <String , Object > hints ) {
88
84
89
- return decodeInternal (this .fluxDecoder , input , elementType , mimeType , hints );
85
+ Flux <TokenBuffer > tokens = Flux .from (input )
86
+ .flatMap (new Jackson2Tokenizer (nonBlockingParser (), true ));
87
+
88
+ return decodeInternal (tokens , elementType , mimeType , hints );
90
89
}
91
90
92
91
@ Override
93
92
public Mono <Object > decodeToMono (Publisher <DataBuffer > input , ResolvableType elementType ,
94
93
@ Nullable MimeType mimeType , @ Nullable Map <String , Object > hints ) {
95
94
96
- return decodeInternal (this .monoDecoder , input , elementType , mimeType , hints ).singleOrEmpty ();
95
+ Flux <TokenBuffer > tokens = Flux .from (input )
96
+ .flatMap (new Jackson2Tokenizer (nonBlockingParser (), false ));
97
+
98
+ return decodeInternal (tokens , elementType , mimeType , hints ).singleOrEmpty ();
97
99
}
98
100
99
- private Flux <Object > decodeInternal (JsonObjectDecoder objectDecoder , Publisher <DataBuffer > inputStream ,
100
- ResolvableType elementType , @ Nullable MimeType mimeType , @ Nullable Map <String , Object > hints ) {
101
+ private Flux <Object > decodeInternal (Flux <TokenBuffer > tokens ,
102
+ ResolvableType elementType , @ Nullable MimeType mimeType ,
103
+ @ Nullable Map <String , Object > hints ) {
101
104
102
- Assert .notNull (inputStream , "'inputStream ' must not be null" );
105
+ Assert .notNull (tokens , "'tokens ' must not be null" );
103
106
Assert .notNull (elementType , "'elementType' must not be null" );
104
107
105
108
Class <?> contextClass = getParameter (elementType ).map (MethodParameter ::getContainingClass ).orElse (null );
@@ -110,26 +113,21 @@ private Flux<Object> decodeInternal(JsonObjectDecoder objectDecoder, Publisher<D
110
113
objectMapper ().readerWithView (jsonView ).forType (javaType ) :
111
114
objectMapper ().readerFor (javaType ));
112
115
113
- return objectDecoder .decode (inputStream , elementType , mimeType , hints )
114
- .flatMap (dataBuffer -> {
115
- if (dataBuffer .readableByteCount () == 0 ) {
116
- return Mono .empty ();
117
- }
118
- try {
119
- Object value = reader .readValue (dataBuffer .asInputStream ());
120
- DataBufferUtils .release (dataBuffer );
121
- return Mono .just (value );
122
- }
123
- catch (InvalidDefinitionException ex ) {
124
- return Mono .error (new CodecException ("Type definition error: " + ex .getType (), ex ));
125
- }
126
- catch (JsonProcessingException ex ) {
127
- return Mono .error (new DecodingException ("JSON decoding error: " + ex .getOriginalMessage (), ex ));
128
- }
129
- catch (IOException ex ) {
130
- return Mono .error (new DecodingException ("I/O error while parsing input stream" , ex ));
131
- }
132
- });
116
+ return tokens .flatMap (tokenBuffer -> {
117
+ try {
118
+ Object value = reader .readValue (tokenBuffer .asParser ());
119
+ return Mono .just (value );
120
+ }
121
+ catch (InvalidDefinitionException ex ) {
122
+ return Mono .error (new CodecException ("Type definition error: " + ex .getType (), ex ));
123
+ }
124
+ catch (JsonProcessingException ex ) {
125
+ return Mono .error (new DecodingException ("JSON decoding error: " + ex .getOriginalMessage (), ex ));
126
+ }
127
+ catch (IOException ex ) {
128
+ return Mono .error (new DecodingException ("I/O error while parsing input stream" , ex ));
129
+ }
130
+ });
133
131
}
134
132
135
133
@@ -147,4 +145,13 @@ protected <A extends Annotation> A getAnnotation(MethodParameter parameter, Clas
147
145
return parameter .getParameterAnnotation (annotType );
148
146
}
149
147
148
+ private JsonParser nonBlockingParser () {
149
+ try {
150
+ JsonFactory factory = this .objectMapper ().getFactory ();
151
+ return factory .createNonBlockingByteArrayParser ();
152
+ }
153
+ catch (IOException ex ) {
154
+ throw new RuntimeIOException (ex );
155
+ }
156
+ }
150
157
}
0 commit comments