Skip to content

Commit c4aa8e1

Browse files
dstepanovkrisfoster
authored andcommitted
fix: Correct order of body handlers (micronaut-projects#11069)
Close: micronaut-projects#11068
1 parent c57994d commit c4aa8e1

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

http-server-netty/src/test/groovy/io/micronaut/http/server/netty/errors/ErrorSpec.groovy

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package io.micronaut.http.server.netty.errors
1717

1818
import groovy.json.JsonSlurper
1919
import io.micronaut.context.annotation.Property
20+
import io.micronaut.context.annotation.Requires
2021
import io.micronaut.core.annotation.NonNull
2122
import io.micronaut.core.async.annotation.SingleResult
2223
import io.micronaut.core.type.Argument
@@ -65,6 +66,8 @@ import java.time.Instant
6566
*/
6667
class ErrorSpec extends AbstractMicronautSpec {
6768

69+
static final String SPEC = "ErrorSpec"
70+
6871
void "test 500 server error"() {
6972
given:
7073
HttpResponse response = Flux.from(httpClient.exchange(
@@ -338,6 +341,7 @@ X-Long-Header: $longString\r
338341
response.header(HttpHeaders.CONTENT_TYPE) == MediaType.APPLICATION_JSON
339342
}
340343

344+
@Requires(property = 'spec.name', value = SPEC)
341345
@Controller('/errors')
342346
static class ErrorController {
343347

@@ -391,6 +395,7 @@ X-Long-Header: $longString\r
391395
}
392396
}
393397

398+
@Requires(property = 'spec.name', value = SPEC)
394399
@Controller('/errors/loop')
395400
static class ErrorLoopController {
396401

@@ -405,6 +410,7 @@ X-Long-Header: $longString\r
405410
}
406411
}
407412

413+
@Requires(property = 'spec.name', value = SPEC)
408414
@Controller('/errors/loop/handler')
409415
static class ErrorLoopHandlerController {
410416

@@ -414,6 +420,7 @@ X-Long-Header: $longString\r
414420
}
415421
}
416422

423+
@Requires(property = 'spec.name', value = SPEC)
417424
@Controller('/errors/injection')
418425
static class ErrorInjectionController {
419426

@@ -430,6 +437,7 @@ X-Long-Header: $longString\r
430437
}
431438
}
432439

440+
@Requires(property = 'spec.name', value = SPEC)
433441
@Controller('/errors/encoding-error/handled')
434442
static class ErrorEncodingHandlerController {
435443
@Get
@@ -443,6 +451,7 @@ X-Long-Header: $longString\r
443451
}
444452
}
445453

454+
@Requires(property = 'spec.name', value = SPEC)
446455
@Controller('/errors/encoding-error/handled/loop')
447456
static class ErrorEncodingHandlerLoopController {
448457
@Get
@@ -456,6 +465,7 @@ X-Long-Header: $longString\r
456465
}
457466
}
458467

468+
@Requires(property = 'spec.name', value = SPEC)
459469
@Controller('/errors/media-type')
460470
static class MediaTypeErrorController {
461471
@Get
@@ -464,6 +474,7 @@ X-Long-Header: $longString\r
464474
}
465475
}
466476

477+
@Requires(property = 'spec.name', value = SPEC)
467478
@Singleton
468479
@Produces("my/mediatype")
469480
static class ThrowingWriter implements MessageBodyWriter<Instant> {
@@ -473,6 +484,7 @@ X-Long-Header: $longString\r
473484
}
474485
}
475486

487+
@Requires(property = 'spec.name', value = SPEC)
476488
@Produces(value = MediaType.TEXT_HTML)
477489
@Singleton
478490
static class ContentTypeExceptionHandler implements ExceptionHandler<ContentTypeExceptionHandlerException, HttpResponse<String>> {
@@ -487,6 +499,7 @@ X-Long-Header: $longString\r
487499

488500
static class LoopingException extends RuntimeException {}
489501

502+
@Requires(property = 'spec.name', value = SPEC)
490503
@Singleton
491504
static class LoopingExceptionHandler implements ExceptionHandler<LoopingException, String> {
492505
@Override

http/src/main/java/io/micronaut/http/body/ConversionTextPlainHandler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
import io.micronaut.context.annotation.BootstrapContextCompatible;
1919
import io.micronaut.context.annotation.Requires;
2020
import io.micronaut.core.annotation.Internal;
21+
import io.micronaut.core.annotation.Order;
2122
import io.micronaut.core.convert.ConversionService;
2223
import io.micronaut.core.io.buffer.ByteBuffer;
2324
import io.micronaut.core.io.buffer.ReferenceCounted;
25+
import io.micronaut.core.order.Ordered;
2426
import io.micronaut.core.type.Argument;
2527
import io.micronaut.core.type.Headers;
2628
import io.micronaut.core.type.MutableHeaders;
@@ -43,8 +45,9 @@
4345
*
4446
* @since 4.0.0
4547
* @author Jonas Konrad
46-
* @param <T> The tye
48+
* @param <T> The type
4749
*/
50+
@Order(Ordered.HIGHEST_PRECEDENCE)
4851
@Produces(MediaType.TEXT_PLAIN)
4952
@Consumes(MediaType.TEXT_PLAIN)
5053
@Singleton

http/src/main/java/io/micronaut/http/body/DefaultMessageBodyHandlerRegistry.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.lang.annotation.Annotation;
3535
import java.util.ArrayList;
3636
import java.util.Collection;
37+
import java.util.Comparator;
3738
import java.util.List;
3839
import java.util.Objects;
3940

@@ -139,26 +140,39 @@ private MediaTypeQualifier(Argument<?> type,
139140
@Override
140141
public <K extends BeanType<T>> Collection<K> filter(Class<T> beanType, Collection<K> candidates) {
141142
List<K> all = new ArrayList<>(candidates.size());
142-
List<K> matchesMediaType = new ArrayList<>(candidates.size());
143-
List<K> matchesAll = new ArrayList<>(candidates.size());
144143
for (K candidate : candidates) {
145144
String[] applicableTypes = candidate.getAnnotationMetadata().stringValues(annotationType);
146145
if (applicableTypes.length == 0) {
147-
matchesAll.add(candidate);
146+
all.add(candidate);
148147
continue;
149148
}
150149
for (String mt : applicableTypes) {
151150
if (mediaTypes.contains(new MediaType(mt))) {
152-
matchesMediaType.add(candidate);
151+
all.add(candidate);
152+
break;
153153
}
154154
}
155155
}
156156
// Handlers with a media type defined should have a priority
157-
all.addAll(matchesMediaType);
158-
all.addAll(matchesAll);
157+
all.sort(Comparator.comparingInt(this::findOrder).reversed());
159158
return all;
160159
}
161160

161+
private int findOrder(BeanType<?> beanType) {
162+
int order = 0;
163+
String[] applicableTypes = beanType.getAnnotationMetadata().stringValues(annotationType);
164+
int size = mediaTypes.size();
165+
for (String mt : applicableTypes) {
166+
int index = mediaTypes.indexOf(new MediaType(mt));
167+
if (index == -1) {
168+
continue;
169+
}
170+
int compareValue = size - index; // First value should have the priority
171+
order = Integer.max(order, compareValue);
172+
}
173+
return order;
174+
}
175+
162176
private static boolean isInvalidType(List<Argument<?>> consumedType, Argument<?> requiredType) {
163177
Argument<?> argument = consumedType.get(0);
164178
return !(argument.isTypeVariable() || argument.isAssignableFrom(requiredType.getType()));

0 commit comments

Comments
 (0)