Optimize Consumes/ProducesRequestCondition

Before this change Consumes/ProducesRequestCondition shared a common
match method in the package private AbstractMediaTypeExpression. The
benefit, two lines of code, was negligible but was forcing each
condition into parsing the content type of the request body or
evaluating the content type for the response respectively.

This change removes the shared match method and brings it down into
each sub-class resulting in a performance improvement as well as in
simpler code including exception handling.

Issue: SPR-14299
master
Rossen Stoyanchev 8 years ago
parent 27215b5061
commit fc40643033
  1. 17
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractMediaTypeExpression.java
  2. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/AbstractRequestCondition.java
  3. 29
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java
  4. 31
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/condition/ProducesRequestCondition.java

@ -16,13 +16,10 @@
package org.springframework.web.servlet.mvc.condition;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.bind.annotation.RequestMapping;
/**
@ -69,20 +66,6 @@ abstract class AbstractMediaTypeExpression implements Comparable<AbstractMediaTy
return this.isNegated;
}
public final boolean match(HttpServletRequest request) {
try {
boolean match = matchMediaType(request);
return (!this.isNegated ? match : !match);
}
catch (HttpMediaTypeException ex) {
return false;
}
}
protected abstract boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeException;
@Override
public int compareTo(AbstractMediaTypeExpression other) {
return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType());

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.http.InvalidMediaTypeException;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.cors.CorsUtils;
@ -170,10 +171,19 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
if (isEmpty()) {
return this;
}
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>(expressions);
MediaType contentType;
try {
contentType = StringUtils.hasLength(request.getContentType()) ?
MediaType.parseMediaType(request.getContentType()) :
MediaType.APPLICATION_OCTET_STREAM;
}
catch (InvalidMediaTypeException ex) {
return null;
}
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>(this.expressions);
for (Iterator<ConsumeMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
ConsumeMediaTypeExpression expression = iterator.next();
if (!expression.match(request)) {
if (!expression.match(contentType)) {
iterator.remove();
}
}
@ -221,18 +231,9 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
super(mediaType, negated);
}
@Override
protected boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeNotSupportedException {
try {
MediaType contentType = StringUtils.hasLength(request.getContentType()) ?
MediaType.parseMediaType(request.getContentType()) :
MediaType.APPLICATION_OCTET_STREAM;
return getMediaType().includes(contentType);
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(
"Can't parse Content-Type [" + request.getContentType() + "]: " + ex.getMessage());
}
public final boolean match(MediaType contentType) {
boolean match = getMediaType().includes(contentType);
return (!isNegated() ? match : !match);
}
}

@ -49,6 +49,8 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
private final static ProducesRequestCondition PRE_FLIGHT_MATCH = new ProducesRequestCondition();
private static final ProducesRequestCondition EMPTY_CONDITION = new ProducesRequestCondition();
private final List<ProduceMediaTypeExpression> MEDIA_TYPE_ALL_LIST =
Collections.singletonList(new ProduceMediaTypeExpression("*/*"));
@ -187,25 +189,29 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
if (isEmpty()) {
return this;
}
List<MediaType> acceptedMediaTypes;
try {
acceptedMediaTypes = getAcceptedMediaTypes(request);
}
catch (HttpMediaTypeException ex) {
return null;
}
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<ProduceMediaTypeExpression>(expressions);
for (Iterator<ProduceMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) {
ProduceMediaTypeExpression expression = iterator.next();
if (!expression.match(request)) {
if (!expression.match(acceptedMediaTypes)) {
iterator.remove();
}
}
if (!result.isEmpty()) {
return new ProducesRequestCondition(result, this.contentNegotiationManager);
}
try {
if (getAcceptedMediaTypes(request).contains(MediaType.ALL)) {
return new ProducesRequestCondition();
}
else if (acceptedMediaTypes.contains(MediaType.ALL)) {
return EMPTY_CONDITION;
}
catch (HttpMediaTypeException ex) {
// Ignore
else {
return null;
}
return null;
}
/**
@ -314,9 +320,12 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
super(expression);
}
@Override
protected boolean matchMediaType(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException {
List<MediaType> acceptedMediaTypes = getAcceptedMediaTypes(request);
public final boolean match(List<MediaType> acceptedMediaTypes) {
boolean match = matchMediaType(acceptedMediaTypes);
return (!isNegated() ? match : !match);
}
private boolean matchMediaType(List<MediaType> acceptedMediaTypes) {
for (MediaType acceptedMediaType : acceptedMediaTypes) {
if (getMediaType().isCompatibleWith(acceptedMediaType)) {
return true;

Loading…
Cancel
Save