Use consistent class design
Update all classes so that inner classes are always last. Also ensure that utility classes are always final and have a private constructor and make exceptions final whenever possible. Issue: SPR-16968
This commit is contained in:
committed by
Juergen Hoeller
parent
0ad0f341bd
commit
eeebd51f57
@@ -39,7 +39,7 @@ import static java.time.format.DateTimeFormatter.*;
|
||||
* @since 5.0
|
||||
* @see <a href="https://tools.ietf.org/html/rfc2183">RFC 2183</a>
|
||||
*/
|
||||
public class ContentDisposition {
|
||||
public final class ContentDisposition {
|
||||
|
||||
@Nullable
|
||||
private final String type;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2018 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,7 +28,7 @@ import org.springframework.util.InvalidMimeTypeException;
|
||||
@SuppressWarnings("serial")
|
||||
public class InvalidMediaTypeException extends IllegalArgumentException {
|
||||
|
||||
private String mediaType;
|
||||
private final String mediaType;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,13 +40,17 @@ import org.springframework.util.StringUtils;
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.0
|
||||
*/
|
||||
public class MediaTypeFactory {
|
||||
public final class MediaTypeFactory {
|
||||
|
||||
private static final String MIME_TYPES_FILE_NAME = "/org/springframework/http/mime.types";
|
||||
|
||||
private static final MultiValueMap<String, MediaType> fileExtensionToMediaTypes = parseMimeTypes();
|
||||
|
||||
|
||||
private MediaTypeFactory() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the {@code mime.types} file found in the resources. Format is:
|
||||
* <code>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.ClassUtils;
|
||||
* @see ClientCodecConfigurer#create()
|
||||
* @see ServerCodecConfigurer#create()
|
||||
*/
|
||||
class CodecConfigurerFactory {
|
||||
final class CodecConfigurerFactory {
|
||||
|
||||
private static final String DEFAULT_CONFIGURERS_PATH = "CodecConfigurer.properties";
|
||||
|
||||
@@ -59,6 +59,10 @@ class CodecConfigurerFactory {
|
||||
}
|
||||
|
||||
|
||||
private CodecConfigurerFactory() {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends CodecConfigurer> T create(Class<T> ifc) {
|
||||
Class<?> impl = defaultCodecConfigurers.get(ifc);
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.lang.Nullable;
|
||||
* @see ServerSentEventHttpMessageWriter
|
||||
* @see <a href="https://www.w3.org/TR/eventsource/">Server-Sent Events W3C recommendation</a>
|
||||
*/
|
||||
public class ServerSentEvent<T> {
|
||||
public final class ServerSentEvent<T> {
|
||||
|
||||
@Nullable
|
||||
private final String id;
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.springframework.util.Assert;
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.0
|
||||
*/
|
||||
class Jackson2Tokenizer {
|
||||
final class Jackson2Tokenizer {
|
||||
|
||||
private final JsonParser parser;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
class DefaultPathContainer implements PathContainer {
|
||||
final class DefaultPathContainer implements PathContainer {
|
||||
|
||||
private static final MultiValueMap<String, String> EMPTY_MAP = new LinkedMultiValueMap<>(0);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -37,10 +37,10 @@ import org.springframework.util.StringUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class HttpRequestMethodNotSupportedException extends ServletException {
|
||||
|
||||
private String method;
|
||||
private final String method;
|
||||
|
||||
@Nullable
|
||||
private String[] supportedMethods;
|
||||
private final String[] supportedMethods;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -30,7 +30,7 @@ import org.springframework.lang.Nullable;
|
||||
public class HttpSessionRequiredException extends ServletException {
|
||||
|
||||
@Nullable
|
||||
private String expectedAttribute;
|
||||
private final String expectedAttribute;
|
||||
|
||||
|
||||
/**
|
||||
@@ -39,6 +39,7 @@ public class HttpSessionRequiredException extends ServletException {
|
||||
*/
|
||||
public HttpSessionRequiredException(String msg) {
|
||||
super(msg);
|
||||
this.expectedAttribute = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -30,7 +30,7 @@ import org.springframework.web.util.WebUtils;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.3.10
|
||||
*/
|
||||
class RelativeRedirectResponseWrapper extends HttpServletResponseWrapper {
|
||||
final class RelativeRedirectResponseWrapper extends HttpServletResponseWrapper {
|
||||
|
||||
private final HttpStatus redirectStatus;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.1
|
||||
*/
|
||||
public class HandlerTypePredicate implements Predicate<Class<?>> {
|
||||
public final class HandlerTypePredicate implements Predicate<Class<?>> {
|
||||
|
||||
private final Set<String> basePackages;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public abstract class AbstractCookieValueMethodArgumentResolver extends Abstract
|
||||
}
|
||||
|
||||
|
||||
private static class CookieValueNamedValueInfo extends NamedValueInfo {
|
||||
private static final class CookieValueNamedValueInfo extends NamedValueInfo {
|
||||
|
||||
private CookieValueNamedValueInfo(CookieValue annotation) {
|
||||
super(annotation.name(), annotation.required(), annotation.defaultValue());
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMet
|
||||
}
|
||||
|
||||
|
||||
private static class ExpressionValueNamedValueInfo extends NamedValueInfo {
|
||||
private static final class ExpressionValueNamedValueInfo extends NamedValueInfo {
|
||||
|
||||
private ExpressionValueNamedValueInfo(Value annotation) {
|
||||
super("@Value", false, annotation.value());
|
||||
|
||||
@@ -88,7 +88,7 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho
|
||||
}
|
||||
|
||||
|
||||
private static class RequestHeaderNamedValueInfo extends NamedValueInfo {
|
||||
private static final class RequestHeaderNamedValueInfo extends NamedValueInfo {
|
||||
|
||||
private RequestHeaderNamedValueInfo(RequestHeader annotation) {
|
||||
super(annotation.name(), annotation.required(), annotation.defaultValue());
|
||||
|
||||
@@ -62,7 +62,7 @@ import org.springframework.web.server.session.WebSessionManager;
|
||||
* @since 5.0
|
||||
* @see HttpWebHandlerAdapter
|
||||
*/
|
||||
public class WebHttpHandlerBuilder {
|
||||
public final class WebHttpHandlerBuilder {
|
||||
|
||||
/** Well-known name for the target WebHandler in the bean factory. */
|
||||
public static final String WEB_HANDLER_BEAN_NAME = "webHandler";
|
||||
|
||||
@@ -53,6 +53,50 @@ final class HierarchicalUriComponents extends UriComponents {
|
||||
|
||||
private static final String PATH_DELIMITER_STRING = "/";
|
||||
|
||||
/**
|
||||
* Represents an empty path.
|
||||
*/
|
||||
static final PathComponent NULL_PATH_COMPONENT = new PathComponent() {
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPathSegments() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathComponent encode(Charset charset) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathComponent expand(UriTemplateVariables uriVariables) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyToUriComponentsBuilder(UriComponentsBuilder builder) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (this == obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Nullable
|
||||
private final String userInfo;
|
||||
@@ -862,43 +906,6 @@ final class HierarchicalUriComponents extends UriComponents {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents an empty path.
|
||||
*/
|
||||
static final PathComponent NULL_PATH_COMPONENT = new PathComponent() {
|
||||
@Override
|
||||
public String getPath() {
|
||||
return "";
|
||||
}
|
||||
@Override
|
||||
public List<String> getPathSegments() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@Override
|
||||
public PathComponent encode(Charset charset) {
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public void verify() {
|
||||
}
|
||||
@Override
|
||||
public PathComponent expand(UriTemplateVariables uriVariables) {
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public void copyToUriComponentsBuilder(UriComponentsBuilder builder) {
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (this == obj);
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private static class QueryUriTemplateVariables implements UriTemplateVariables {
|
||||
|
||||
private final UriTemplateVariables delegate;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -29,7 +29,12 @@ package org.springframework.web.util;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.1.1
|
||||
*/
|
||||
public class JavaScriptUtils {
|
||||
public final class JavaScriptUtils {
|
||||
|
||||
|
||||
private JavaScriptUtils() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Turn JavaScript special characters into escaped characters.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -170,7 +170,7 @@ public class UriTemplate implements Serializable {
|
||||
/**
|
||||
* Helper to extract variable names and regex for matching to actual URLs.
|
||||
*/
|
||||
private static class TemplateInfo {
|
||||
private static final class TemplateInfo {
|
||||
|
||||
private final List<String> variableNames;
|
||||
|
||||
|
||||
@@ -73,6 +73,25 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
|
||||
private static final PathContainer EMPTY_PATH = PathContainer.parsePath("");
|
||||
|
||||
/**
|
||||
* Comparator that sorts patterns by specificity as follows:
|
||||
* <ol>
|
||||
* <li>Null instances are last.
|
||||
* <li>Catch-all patterns are last.
|
||||
* <li>If both patterns are catch-all, consider the length (longer wins).
|
||||
* <li>Compare wildcard and captured variable count (lower wins).
|
||||
* <li>Consider length (longer wins)
|
||||
* </ol>
|
||||
*/
|
||||
public static final Comparator<PathPattern> SPECIFICITY_COMPARATOR =
|
||||
Comparator.nullsLast(
|
||||
Comparator.<PathPattern>
|
||||
comparingInt(p -> p.isCatchAll() ? 1 : 0)
|
||||
.thenComparingInt(p -> p.isCatchAll() ? scoreByNormalizedLength(p) : 0)
|
||||
.thenComparingInt(PathPattern::getScore)
|
||||
.thenComparingInt(PathPattern::scoreByNormalizedLength)
|
||||
);
|
||||
|
||||
|
||||
/** The text of the parsed pattern. */
|
||||
private final String patternString;
|
||||
@@ -408,97 +427,6 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
return this.patternString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holder for URI variables and path parameters (matrix variables) extracted
|
||||
* based on the pattern for a given matched path.
|
||||
*/
|
||||
public static class PathMatchInfo {
|
||||
|
||||
private static final PathMatchInfo EMPTY =
|
||||
new PathMatchInfo(Collections.emptyMap(), Collections.emptyMap());
|
||||
|
||||
|
||||
private final Map<String, String> uriVariables;
|
||||
|
||||
private final Map<String, MultiValueMap<String, String>> matrixVariables;
|
||||
|
||||
|
||||
PathMatchInfo(Map<String, String> uriVars,
|
||||
@Nullable Map<String, MultiValueMap<String, String>> matrixVars) {
|
||||
|
||||
this.uriVariables = Collections.unmodifiableMap(uriVars);
|
||||
this.matrixVariables = matrixVars != null ?
|
||||
Collections.unmodifiableMap(matrixVars) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the extracted URI variables.
|
||||
*/
|
||||
public Map<String, String> getUriVariables() {
|
||||
return this.uriVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return maps of matrix variables per path segment, keyed off by URI
|
||||
* variable name.
|
||||
*/
|
||||
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
|
||||
return this.matrixVariables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathMatchInfo[uriVariables=" + this.uriVariables + ", " +
|
||||
"matrixVariables=" + this.matrixVariables + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder for the result of a match on the start of a pattern.
|
||||
* Provides access to the remaining path not matched to the pattern as well
|
||||
* as any variables bound in that first part that was matched.
|
||||
*/
|
||||
public static class PathRemainingMatchInfo {
|
||||
|
||||
private final PathContainer pathRemaining;
|
||||
|
||||
private final PathMatchInfo pathMatchInfo;
|
||||
|
||||
|
||||
PathRemainingMatchInfo(PathContainer pathRemaining) {
|
||||
this(pathRemaining, PathMatchInfo.EMPTY);
|
||||
}
|
||||
|
||||
PathRemainingMatchInfo(PathContainer pathRemaining, PathMatchInfo pathMatchInfo) {
|
||||
this.pathRemaining = pathRemaining;
|
||||
this.pathMatchInfo = pathMatchInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the part of a path that was not matched by a pattern.
|
||||
*/
|
||||
public PathContainer getPathRemaining() {
|
||||
return this.pathRemaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return variables that were bound in the part of the path that was
|
||||
* successfully matched or an empty map.
|
||||
*/
|
||||
public Map<String, String> getUriVariables() {
|
||||
return this.pathMatchInfo.getUriVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path parameters for each bound variable.
|
||||
*/
|
||||
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
|
||||
return this.pathMatchInfo.getMatrixVariables();
|
||||
}
|
||||
}
|
||||
|
||||
int getScore() {
|
||||
return this.score;
|
||||
}
|
||||
@@ -554,6 +482,138 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
return this.head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two paths together including a separator if necessary.
|
||||
* Extraneous separators are removed (if the first path
|
||||
* ends with one and the second path starts with one).
|
||||
* @param path1 first path
|
||||
* @param path2 second path
|
||||
* @return joined path that may include separator if necessary
|
||||
*/
|
||||
private String concat(String path1, String path2) {
|
||||
boolean path1EndsWithSeparator = (path1.charAt(path1.length() - 1) == this.separator);
|
||||
boolean path2StartsWithSeparator = (path2.charAt(0) == this.separator);
|
||||
if (path1EndsWithSeparator && path2StartsWithSeparator) {
|
||||
return path1 + path2.substring(1);
|
||||
}
|
||||
else if (path1EndsWithSeparator || path2StartsWithSeparator) {
|
||||
return path1 + path2;
|
||||
}
|
||||
else {
|
||||
return path1 + this.separator + path2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the container is not null and has more than zero elements.
|
||||
* @param container a path container
|
||||
* @return {@code true} has more than zero elements
|
||||
*/
|
||||
private boolean hasLength(@Nullable PathContainer container) {
|
||||
return container != null && container.elements().size() > 0;
|
||||
}
|
||||
|
||||
private static int scoreByNormalizedLength(PathPattern pattern) {
|
||||
return -pattern.getNormalizedLength();
|
||||
}
|
||||
|
||||
private boolean pathContainerIsJustSeparator(PathContainer pathContainer) {
|
||||
return pathContainer.value().length() == 1 &&
|
||||
pathContainer.value().charAt(0) == separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder for URI variables and path parameters (matrix variables) extracted
|
||||
* based on the pattern for a given matched path.
|
||||
*/
|
||||
public static class PathMatchInfo {
|
||||
|
||||
private static final PathMatchInfo EMPTY =
|
||||
new PathMatchInfo(Collections.emptyMap(), Collections.emptyMap());
|
||||
|
||||
|
||||
private final Map<String, String> uriVariables;
|
||||
|
||||
private final Map<String, MultiValueMap<String, String>> matrixVariables;
|
||||
|
||||
|
||||
PathMatchInfo(Map<String, String> uriVars,
|
||||
@Nullable Map<String, MultiValueMap<String, String>> matrixVars) {
|
||||
|
||||
this.uriVariables = Collections.unmodifiableMap(uriVars);
|
||||
this.matrixVariables = matrixVars != null ?
|
||||
Collections.unmodifiableMap(matrixVars) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the extracted URI variables.
|
||||
*/
|
||||
public Map<String, String> getUriVariables() {
|
||||
return this.uriVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return maps of matrix variables per path segment, keyed off by URI
|
||||
* variable name.
|
||||
*/
|
||||
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
|
||||
return this.matrixVariables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathMatchInfo[uriVariables=" + this.uriVariables + ", " +
|
||||
"matrixVariables=" + this.matrixVariables + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Holder for the result of a match on the start of a pattern.
|
||||
* Provides access to the remaining path not matched to the pattern as well
|
||||
* as any variables bound in that first part that was matched.
|
||||
*/
|
||||
public static class PathRemainingMatchInfo {
|
||||
|
||||
private final PathContainer pathRemaining;
|
||||
|
||||
private final PathMatchInfo pathMatchInfo;
|
||||
|
||||
|
||||
PathRemainingMatchInfo(PathContainer pathRemaining) {
|
||||
this(pathRemaining, PathMatchInfo.EMPTY);
|
||||
}
|
||||
|
||||
PathRemainingMatchInfo(PathContainer pathRemaining, PathMatchInfo pathMatchInfo) {
|
||||
this.pathRemaining = pathRemaining;
|
||||
this.pathMatchInfo = pathMatchInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the part of a path that was not matched by a pattern.
|
||||
*/
|
||||
public PathContainer getPathRemaining() {
|
||||
return this.pathRemaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return variables that were bound in the part of the path that was
|
||||
* successfully matched or an empty map.
|
||||
*/
|
||||
public Map<String, String> getUriVariables() {
|
||||
return this.pathMatchInfo.getUriVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path parameters for each bound variable.
|
||||
*/
|
||||
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
|
||||
return this.pathMatchInfo.getMatrixVariables();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates context when attempting a match. Includes some fixed state like the
|
||||
* candidate currently being considered for a match but also some accumulators for
|
||||
@@ -642,65 +702,4 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two paths together including a separator if necessary.
|
||||
* Extraneous separators are removed (if the first path
|
||||
* ends with one and the second path starts with one).
|
||||
* @param path1 first path
|
||||
* @param path2 second path
|
||||
* @return joined path that may include separator if necessary
|
||||
*/
|
||||
private String concat(String path1, String path2) {
|
||||
boolean path1EndsWithSeparator = (path1.charAt(path1.length() - 1) == this.separator);
|
||||
boolean path2StartsWithSeparator = (path2.charAt(0) == this.separator);
|
||||
if (path1EndsWithSeparator && path2StartsWithSeparator) {
|
||||
return path1 + path2.substring(1);
|
||||
}
|
||||
else if (path1EndsWithSeparator || path2StartsWithSeparator) {
|
||||
return path1 + path2;
|
||||
}
|
||||
else {
|
||||
return path1 + this.separator + path2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the container is not null and has more than zero elements.
|
||||
* @param container a path container
|
||||
* @return {@code true} has more than zero elements
|
||||
*/
|
||||
private boolean hasLength(@Nullable PathContainer container) {
|
||||
return container != null && container.elements().size() > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Comparator that sorts patterns by specificity as follows:
|
||||
* <ol>
|
||||
* <li>Null instances are last.
|
||||
* <li>Catch-all patterns are last.
|
||||
* <li>If both patterns are catch-all, consider the length (longer wins).
|
||||
* <li>Compare wildcard and captured variable count (lower wins).
|
||||
* <li>Consider length (longer wins)
|
||||
* </ol>
|
||||
*/
|
||||
public static final Comparator<PathPattern> SPECIFICITY_COMPARATOR =
|
||||
Comparator.nullsLast(
|
||||
Comparator.<PathPattern>
|
||||
comparingInt(p -> p.isCatchAll() ? 1 : 0)
|
||||
.thenComparingInt(p -> p.isCatchAll() ? scoreByNormalizedLength(p) : 0)
|
||||
.thenComparingInt(PathPattern::getScore)
|
||||
.thenComparingInt(PathPattern::scoreByNormalizedLength)
|
||||
);
|
||||
|
||||
private static int scoreByNormalizedLength(PathPattern pattern) {
|
||||
return -pattern.getNormalizedLength();
|
||||
}
|
||||
|
||||
private boolean pathContainerIsJustSeparator(PathContainer pathContainer) {
|
||||
return pathContainer.value().length() == 1 &&
|
||||
pathContainer.value().charAt(0) == separator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user