15
15
*/
16
16
package io .micronaut .http .bind ;
17
17
18
+ import io .micronaut .core .annotation .AnnotationMetadata ;
19
+ import io .micronaut .core .annotation .AnnotationUtil ;
18
20
import io .micronaut .core .annotation .NonNull ;
19
21
import io .micronaut .core .bind .ArgumentBinder ;
20
22
import io .micronaut .core .bind .annotation .Bindable ;
33
35
import io .micronaut .http .annotation .Body ;
34
36
import io .micronaut .http .bind .binders .AnnotatedRequestArgumentBinder ;
35
37
import io .micronaut .http .bind .binders .ContinuationArgumentBinder ;
36
- import io .micronaut .http .bind .binders .CookieObjectArgumentBinder ;
37
38
import io .micronaut .http .bind .binders .CookieAnnotationBinder ;
39
+ import io .micronaut .http .bind .binders .CookieObjectArgumentBinder ;
38
40
import io .micronaut .http .bind .binders .DefaultBodyAnnotationBinder ;
39
41
import io .micronaut .http .bind .binders .DefaultUnmatchedRequestArgumentBinder ;
40
42
import io .micronaut .http .bind .binders .HeaderAnnotationBinder ;
48
50
import io .micronaut .http .bind .binders .TypedRequestArgumentBinder ;
49
51
import io .micronaut .http .cookie .Cookie ;
50
52
import io .micronaut .http .cookie .Cookies ;
53
+ import io .micronaut .inject .annotation .AnnotationMetadataHierarchy ;
54
+ import io .micronaut .inject .annotation .MutableAnnotationMetadata ;
51
55
import jakarta .inject .Inject ;
52
56
import jakarta .inject .Singleton ;
53
57
71
75
public class DefaultRequestBinderRegistry implements RequestBinderRegistry {
72
76
73
77
private static final long CACHE_MAX_SIZE = 30 ;
74
-
78
+ private static final AnnotationMetadata NULLABLE_ANNOTATION_METADATA ;
75
79
private final Map <Class <? extends Annotation >, RequestArgumentBinder > byAnnotation = new LinkedHashMap <>();
76
80
private final Map <TypeAndAnnotation , RequestArgumentBinder > byTypeAndAnnotation = new LinkedHashMap <>();
77
81
private final Map <Integer , RequestArgumentBinder > byType = new LinkedHashMap <>();
@@ -81,6 +85,12 @@ public class DefaultRequestBinderRegistry implements RequestBinderRegistry {
81
85
private final List <RequestArgumentBinder <Object >> unmatchedBinders = new ArrayList <>();
82
86
private final DefaultUnmatchedRequestArgumentBinder defaultUnmatchedRequestArgumentBinder ;
83
87
88
+ static {
89
+ MutableAnnotationMetadata nullable = new MutableAnnotationMetadata ();
90
+ nullable .addAnnotation (AnnotationUtil .NULLABLE , Map .of ());
91
+ NULLABLE_ANNOTATION_METADATA = nullable ;
92
+ }
93
+
84
94
/**
85
95
* @param conversionService The conversion service
86
96
* @param binders The request argument binders
@@ -268,7 +278,14 @@ private static ArgumentBinder.BindingResult<? extends HttpRequest<?>> convertBod
268
278
.filter (arg -> arg .getType () != Void .class );
269
279
if (typeVariable .isPresent ()) {
270
280
@ SuppressWarnings ("unchecked" )
271
- ArgumentConversionContext <Object > unwrappedConversionContext = ConversionContext .of ((Argument <Object >) typeVariable .get ());
281
+ Argument <Object > argument = (Argument <Object >) typeVariable .get ();
282
+ argument = argument .withAnnotationMetadata (
283
+ new AnnotationMetadataHierarchy (
284
+ argument .getAnnotationMetadata (),
285
+ NULLABLE_ANNOTATION_METADATA // HttpRequest's body can be null
286
+ )
287
+ );
288
+ ArgumentConversionContext <Object > unwrappedConversionContext = ConversionContext .of (argument );
272
289
ArgumentBinder .BindingResult <Object > bodyBound = bodyAnnotationBinder .bindFullBody (unwrappedConversionContext , source );
273
290
// can't use flatMap here because we return a present optional even when the body conversion failed
274
291
return new PendingRequestBindingResult <>() {
@@ -286,14 +303,14 @@ public List<ConversionError> getConversionErrors() {
286
303
public Optional <HttpRequest <?>> getValue () {
287
304
Optional <Object > body = bodyBound .getValue ();
288
305
if (pushCapable ) {
289
- return Optional .of (new PushCapableRequestWrapper <Object >((HttpRequest <Object >) source , (PushCapableHttpRequest <?>) source ) {
306
+ return Optional .of (new PushCapableRequestWrapper <>((HttpRequest <Object >) source , (PushCapableHttpRequest <?>) source ) {
290
307
@ Override
291
308
public Optional <Object > getBody () {
292
309
return body ;
293
310
}
294
311
});
295
312
} else {
296
- return Optional .of (new HttpRequestWrapper <Object >((HttpRequest <Object >) source ) {
313
+ return Optional .of (new HttpRequestWrapper <>((HttpRequest <Object >) source ) {
297
314
@ Override
298
315
public Optional <Object > getBody () {
299
316
return body ;
0 commit comments