Skip to content

Commit

Permalink
Optimal initialization of empty request mapping conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
rstoyanchev authored and xcl(徐程林) committed Aug 16, 2020
1 parent 73f6088 commit ff38b9c
Show file tree
Hide file tree
Showing 18 changed files with 479 additions and 284 deletions.
Expand Up @@ -29,6 +29,7 @@
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.cors.reactive.CorsUtils;
Expand Down Expand Up @@ -75,39 +76,39 @@ public ConsumesRequestCondition(String... consumes) {
* @param headers as described in {@link RequestMapping#headers()}
*/
public ConsumesRequestCondition(String[] consumes, String[] headers) {
this.expressions = new ArrayList<>(parseExpressions(consumes, headers));
this.expressions = parseExpressions(consumes, headers);
if (this.expressions.size() > 1) {
Collections.sort(this.expressions);
}
}

/**
* Private constructor for internal when creating matching conditions.
* Note the expressions List is neither sorted nor deep copied.
*/
private ConsumesRequestCondition(List<ConsumeMediaTypeExpression> expressions) {
this.expressions = expressions;
}


private static Set<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<>();
if (headers != null) {
private static List<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
Set<ConsumeMediaTypeExpression> result = null;
if (!ObjectUtils.isEmpty(headers)) {
for (String header : headers) {
HeadersRequestCondition.HeaderExpression expr = new HeadersRequestCondition.HeaderExpression(header);
if ("Content-Type".equalsIgnoreCase(expr.name)) {
result = (result != null ? result : new LinkedHashSet<>());
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
result.add(new ConsumeMediaTypeExpression(mediaType, expr.isNegated));
}
}
}
}
if (consumes != null) {
if (!ObjectUtils.isEmpty(consumes)) {
result = (result != null ? result : new LinkedHashSet<>());
for (String consume : consumes) {
result.add(new ConsumeMediaTypeExpression(consume));
}
}
return result;
return (result != null ? new ArrayList<>(result) : Collections.emptyList());
}

/**
* Private constructor for internal when creating matching conditions.
*/
private ConsumesRequestCondition(List<ConsumeMediaTypeExpression> expressions) {
this.expressions = expressions;
}


Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
Expand All @@ -17,10 +17,12 @@
package org.springframework.web.reactive.result.condition;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
Expand Down Expand Up @@ -52,28 +54,29 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
* if 0, the condition will match to every request
*/
public HeadersRequestCondition(String... headers) {
this(parseExpressions(headers));
this.expressions = parseExpressions(headers);
}

private HeadersRequestCondition(Set<HeaderExpression> conditions) {
this.expressions = conditions;
}


private static Set<HeaderExpression> parseExpressions(String... headers) {
Set<HeaderExpression> expressions = new LinkedHashSet<>();
if (headers != null) {
Set<HeaderExpression> result = null;
if (!ObjectUtils.isEmpty(headers)) {
for (String header : headers) {
HeaderExpression expr = new HeaderExpression(header);
if ("Accept".equalsIgnoreCase(expr.name) || "Content-Type".equalsIgnoreCase(expr.name)) {
continue;
}
expressions.add(expr);
result = (result != null ? result : new LinkedHashSet<>(headers.length));
result.add(expr);
}
}
return expressions;
return (result != null ? result : Collections.emptySet());
}

private HeadersRequestCondition(Set<HeaderExpression> conditions) {
this.expressions = conditions;
}


/**
* Return the contained request header expressions.
*/
Expand All @@ -97,6 +100,15 @@ protected String getToStringInfix() {
*/
@Override
public HeadersRequestCondition combine(HeadersRequestCondition other) {
if (isEmpty() && other.isEmpty()) {
return this;
}
else if (other.isEmpty()) {
return this;
}
else if (isEmpty()) {
return other;
}
Set<HeaderExpression> set = new LinkedHashSet<>(this.expressions);
set.addAll(other.expressions);
return new HeadersRequestCondition(set);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
Expand All @@ -21,6 +21,7 @@
import java.util.LinkedHashSet;
import java.util.Set;

import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.ServerWebExchange;

Expand All @@ -42,22 +43,22 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
* if 0, the condition will match to every request.
*/
public ParamsRequestCondition(String... params) {
this(parseExpressions(params));
this.expressions = parseExpressions(params);
}

private ParamsRequestCondition(Collection<ParamExpression> conditions) {
this.expressions = Collections.unmodifiableSet(new LinkedHashSet<>(conditions));
private static Set<ParamExpression> parseExpressions(String... params) {
if (ObjectUtils.isEmpty(params)) {
return Collections.emptySet();
}
Set<ParamExpression> result = new LinkedHashSet<>(params.length);
for (String param : params) {
result.add(new ParamExpression(param));
}
return result;
}


private static Collection<ParamExpression> parseExpressions(String... params) {
Set<ParamExpression> expressions = new LinkedHashSet<>();
if (params != null) {
for (String param : params) {
expressions.add(new ParamExpression(param));
}
}
return expressions;
private ParamsRequestCondition(Set<ParamExpression> conditions) {
this.expressions = conditions;
}


Expand All @@ -84,6 +85,15 @@ protected String getToStringInfix() {
*/
@Override
public ParamsRequestCondition combine(ParamsRequestCondition other) {
if (isEmpty() && other.isEmpty()) {
return this;
}
else if (other.isEmpty()) {
return this;
}
else if (isEmpty()) {
return other;
}
Set<ParamExpression> set = new LinkedHashSet<>(this.expressions);
set.addAll(other.expressions);
return new ParamsRequestCondition(set);
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
Expand Down Expand Up @@ -27,6 +27,7 @@

import org.springframework.http.server.PathContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
Expand All @@ -41,7 +42,7 @@
*/
public final class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {

private static final SortedSet<PathPattern> EMPTY_PATTERNS =
private static final SortedSet<PathPattern> EMPTY_PATH_PATTERN =
new TreeSet<>(Collections.singleton(new PathPatternParser().parse("")));


Expand All @@ -53,21 +54,21 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
* @param patterns 0 or more URL patterns; if 0 the condition will match to every request.
*/
public PatternsRequestCondition(PathPattern... patterns) {
this(Arrays.asList(patterns));
this(ObjectUtils.isEmpty(patterns) ? Collections.emptyList() : Arrays.asList(patterns));
}

/**
* Creates a new instance with the given URL patterns.
*/
public PatternsRequestCondition(List<PathPattern> patterns) {
this(patterns.isEmpty() ? EMPTY_PATTERNS : new TreeSet<>(patterns));
this.patterns = (patterns.isEmpty() ? EMPTY_PATH_PATTERN : new TreeSet<>(patterns));
}


private PatternsRequestCondition(SortedSet<PathPattern> patterns) {
this.patterns = patterns;
}


public Set<PathPattern> getPatterns() {
return this.patterns;
}
Expand All @@ -94,25 +95,28 @@ protected String getToStringInfix() {
*/
@Override
public PatternsRequestCondition combine(PatternsRequestCondition other) {
SortedSet<PathPattern> combined;
if (!this.patterns.isEmpty() && !other.patterns.isEmpty()) {
combined = new TreeSet<>();
if (isEmptyPathPattern() && other.isEmptyPathPattern()) {
return this;
}
else if (other.isEmptyPathPattern()) {
return this;
}
else if (isEmptyPathPattern()) {
return other;
}
else {
SortedSet<PathPattern> combined = new TreeSet<>();
for (PathPattern pattern1 : this.patterns) {
for (PathPattern pattern2 : other.patterns) {
combined.add(pattern1.combine(pattern2));
}
}
return new PatternsRequestCondition(combined);
}
else if (!this.patterns.isEmpty()) {
combined = this.patterns;
}
else if (!other.patterns.isEmpty()) {
combined = other.patterns;
}
else {
combined = EMPTY_PATTERNS;
}
return new PatternsRequestCondition(combined);
}

private boolean isEmptyPathPattern() {
return this.patterns == EMPTY_PATH_PATTERN;
}

/**
Expand All @@ -126,31 +130,21 @@ else if (!other.patterns.isEmpty()) {
@Override
@Nullable
public PatternsRequestCondition getMatchingCondition(ServerWebExchange exchange) {
if (this.patterns.isEmpty()) {
return this;
}
SortedSet<PathPattern> matches = getMatchingPatterns(exchange);
return (!matches.isEmpty() ? new PatternsRequestCondition(matches) : null);
return (matches != null ? new PatternsRequestCondition(matches) : null);
}

/**
* Find the patterns matching the given lookup path. Invoking this method should
* yield results equivalent to those of calling
* {@link #getMatchingCondition(ServerWebExchange)}.
* This method is provided as an alternative to be used if no request is available
* (e.g. introspection, tooling, etc).
* @param exchange the current exchange
* @return a sorted set of matching patterns sorted with the closest match first
*/
@Nullable
private SortedSet<PathPattern> getMatchingPatterns(ServerWebExchange exchange) {
PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
TreeSet<PathPattern> pathPatterns = new TreeSet<>();
TreeSet<PathPattern> result = null;
for (PathPattern pattern : this.patterns) {
if (pattern.matches(lookupPath)) {
pathPatterns.add(pattern);
result = (result != null ? result : new TreeSet<>());
result.add(pattern);
}
}
return pathPatterns;
return result;
}

/**
Expand Down

0 comments on commit ff38b9c

Please sign in to comment.