Browse Source

Avoid regex pattern matching for simple String replacement steps

Issue: SPR-17279
pull/1942/head
Juergen Hoeller 8 years ago
parent
commit
34663300a6
  1. 4
      spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterFactory.java
  2. 5
      spring-context/src/main/java/org/springframework/instrument/classloading/WeavingTransformer.java
  3. 11
      spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java
  4. 9
      spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java
  5. 2
      spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java
  6. 5
      spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java
  7. 6
      spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java
  8. 13
      spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java
  9. 17
      spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java
  10. 7
      spring-webmvc/src/main/java/org/springframework/web/servlet/tags/UrlTag.java
  11. 2
      spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupConfigurer.java
  12. 5
      spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsUrlInfo.java
  13. 5
      spring-websocket/src/main/java/org/springframework/web/socket/sockjs/frame/SockJsFrame.java

4
spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterFactory.java

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -183,7 +183,7 @@ public class DateTimeFormatterFactory {
// Using strict parsing to align with Joda-Time and standard DateFormat behavior: // Using strict parsing to align with Joda-Time and standard DateFormat behavior:
// otherwise, an overflow like e.g. Feb 29 for a non-leap-year wouldn't get rejected. // otherwise, an overflow like e.g. Feb 29 for a non-leap-year wouldn't get rejected.
// However, with strict parsing, a year digit needs to be specified as 'u'... // However, with strict parsing, a year digit needs to be specified as 'u'...
String patternToUse = this.pattern.replace("yy", "uu"); String patternToUse = StringUtils.replace(this.pattern, "yy", "uu");
dateTimeFormatter = DateTimeFormatter.ofPattern(patternToUse).withResolverStyle(ResolverStyle.STRICT); dateTimeFormatter = DateTimeFormatter.ofPattern(patternToUse).withResolverStyle(ResolverStyle.STRICT);
} }
else if (this.iso != null && this.iso != ISO.NONE) { else if (this.iso != null && this.iso != ISO.NONE) {

5
spring-context/src/main/java/org/springframework/instrument/classloading/WeavingTransformer.java

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,6 +24,7 @@ import java.util.List;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/** /**
* ClassFileTransformer-based weaver, allowing for a list of transformers to be * ClassFileTransformer-based weaver, allowing for a list of transformers to be
@ -73,7 +74,7 @@ public class WeavingTransformer {
* @return (possibly transformed) class byte definition * @return (possibly transformed) class byte definition
*/ */
public byte[] transformIfNecessary(String className, byte[] bytes) { public byte[] transformIfNecessary(String className, byte[] bytes) {
String internalName = className.replace(".", "/"); String internalName = StringUtils.replace(className, ".", "/");
return transformIfNecessary(className, internalName, bytes, null); return transformIfNecessary(className, internalName, bytes, null);
} }

11
spring-expression/src/main/java/org/springframework/expression/spel/ast/StringLiteral.java

@ -19,6 +19,7 @@ package org.springframework.expression.spel.ast;
import org.springframework.asm.MethodVisitor; import org.springframework.asm.MethodVisitor;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow; import org.springframework.expression.spel.CodeFlow;
import org.springframework.util.StringUtils;
/** /**
* Expression language AST node that represents a string literal. * Expression language AST node that represents a string literal.
@ -33,9 +34,13 @@ public class StringLiteral extends Literal {
public StringLiteral(String payload, int pos, String value) { public StringLiteral(String payload, int pos, String value) {
super(payload,pos); super(payload, pos);
value = value.substring(1, value.length() - 1);
this.value = new TypedValue(value.replaceAll("''", "'").replaceAll("\"\"", "\"")); String valueWithinQuotes = value.substring(1, value.length() - 1);
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "''", "'");
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "\"\"", "\"");
this.value = new TypedValue(valueWithinQuotes);
this.exitTypeDescriptor = "Ljava/lang/String"; this.exitTypeDescriptor = "Ljava/lang/String";
} }

9
spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelCompiler.java

@ -36,6 +36,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/** /**
* A SpelCompiler will take a regular parsed expression and create (and load) a class * A SpelCompiler will take a regular parsed expression and create (and load) a class
@ -132,9 +133,9 @@ public final class SpelCompiler implements Opcodes {
@Nullable @Nullable
private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl expressionToCompile) { private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl expressionToCompile) {
// Create class outline 'spel/ExNNN extends org.springframework.expression.spel.CompiledExpression' // Create class outline 'spel/ExNNN extends org.springframework.expression.spel.CompiledExpression'
String clazzName = "spel/Ex" + getNextSuffix(); String className = "spel/Ex" + getNextSuffix();
ClassWriter cw = new ExpressionClassWriter(); ClassWriter cw = new ExpressionClassWriter();
cw.visit(V1_5, ACC_PUBLIC, clazzName, null, "org/springframework/expression/spel/CompiledExpression", null); cw.visit(V1_5, ACC_PUBLIC, className, null, "org/springframework/expression/spel/CompiledExpression", null);
// Create default constructor // Create default constructor
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
@ -152,7 +153,7 @@ public final class SpelCompiler implements Opcodes {
new String[ ]{"org/springframework/expression/EvaluationException"}); new String[ ]{"org/springframework/expression/EvaluationException"});
mv.visitCode(); mv.visitCode();
CodeFlow cf = new CodeFlow(clazzName, cw); CodeFlow cf = new CodeFlow(className, cw);
// Ask the expression AST to generate the body of the method // Ask the expression AST to generate the body of the method
try { try {
@ -181,7 +182,7 @@ public final class SpelCompiler implements Opcodes {
byte[] data = cw.toByteArray(); byte[] data = cw.toByteArray();
// TODO need to make this conditionally occur based on a debug flag // TODO need to make this conditionally occur based on a debug flag
// dump(expressionToCompile.toStringAST(), clazzName, data); // dump(expressionToCompile.toStringAST(), clazzName, data);
return loadClass(clazzName.replaceAll("/", "."), data); return loadClass(StringUtils.replace(className, "/", "."), data);
} }
/** /**

2
spring-jdbc/src/main/java/org/springframework/jdbc/core/BeanPropertyRowMapper.java

@ -292,7 +292,7 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
for (int index = 1; index <= columnCount; index++) { for (int index = 1; index <= columnCount; index++) {
String column = JdbcUtils.lookupColumnName(rsmd, index); String column = JdbcUtils.lookupColumnName(rsmd, index);
String field = lowerCaseName(column.replaceAll(" ", "")); String field = lowerCaseName(StringUtils.delete(column, " "));
PropertyDescriptor pd = (this.mappedFields != null ? this.mappedFields.get(field) : null); PropertyDescriptor pd = (this.mappedFields != null ? this.mappedFields.get(field) : null);
if (pd != null) { if (pd != null) {
try { try {

5
spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java

@ -38,6 +38,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/** /**
* {@code HttpMessageWriter} for {@code "text/event-stream"} responses. * {@code HttpMessageWriter} for {@code "text/event-stream"} responses.
@ -135,7 +136,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
writeField("retry", retry.toMillis(), sb); writeField("retry", retry.toMillis(), sb);
} }
if (comment != null) { if (comment != null) {
sb.append(':').append(comment.replaceAll("\\n", "\n:")).append("\n"); sb.append(':').append(StringUtils.replace(comment, "\n", "\n:")).append("\n");
} }
if (data != null) { if (data != null) {
sb.append("data:"); sb.append("data:");
@ -164,7 +165,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
if (data instanceof String) { if (data instanceof String) {
String text = (String) data; String text = (String) data;
return Flux.from(encodeText(text.replaceAll("\\n", "\ndata:") + "\n", mediaType, factory)); return Flux.from(encodeText(StringUtils.replace(text, "\n", "\ndata:") + "\n", mediaType, factory));
} }
if (this.encoder == null) { if (this.encoder == null) {

6
spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java

@ -287,13 +287,15 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
// We will perform this validation... // We will perform this validation...
etag = padEtagIfNecessary(etag); etag = padEtagIfNecessary(etag);
if (etag.startsWith("W/")) {
etag = etag.substring(2);
}
while (ifNoneMatch.hasMoreElements()) { while (ifNoneMatch.hasMoreElements()) {
String clientETags = ifNoneMatch.nextElement(); String clientETags = ifNoneMatch.nextElement();
Matcher etagMatcher = ETAG_HEADER_VALUE_PATTERN.matcher(clientETags); Matcher etagMatcher = ETAG_HEADER_VALUE_PATTERN.matcher(clientETags);
// Compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3 // Compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3
while (etagMatcher.find()) { while (etagMatcher.find()) {
if (StringUtils.hasLength(etagMatcher.group()) && if (StringUtils.hasLength(etagMatcher.group()) && etag.equals(etagMatcher.group(3))) {
etag.replaceFirst("^W/", "").equals(etagMatcher.group(3))) {
this.notModified = true; this.notModified = true;
break; break;
} }

13
spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java

@ -126,8 +126,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
String responseETag = generateETagHeaderValue(responseWrapper.getContentInputStream(), this.writeWeakETag); String responseETag = generateETagHeaderValue(responseWrapper.getContentInputStream(), this.writeWeakETag);
rawResponse.setHeader(HEADER_ETAG, responseETag); rawResponse.setHeader(HEADER_ETAG, responseETag);
String requestETag = request.getHeader(HEADER_IF_NONE_MATCH); String requestETag = request.getHeader(HEADER_IF_NONE_MATCH);
if (requestETag != null && ("*".equals(requestETag) || responseETag.equals(requestETag) || if (requestETag != null && ("*".equals(requestETag) || compareETagHeaderValue(requestETag, responseETag))) {
responseETag.replaceFirst("^W/", "").equals(requestETag.replaceFirst("^W/", "")))) {
rawResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED); rawResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
} }
else { else {
@ -184,6 +183,16 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
return builder.toString(); return builder.toString();
} }
private boolean compareETagHeaderValue(String requestETag, String responseETag) {
if (requestETag.startsWith("W/")) {
requestETag = requestETag.substring(2);
}
if (responseETag.startsWith("W/")) {
responseETag = responseETag.substring(2);
}
return requestETag.equals(responseETag);
}
/** /**
* This method can be used to disable the content caching response wrapper * This method can be used to disable the content caching response wrapper

17
spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java

@ -318,12 +318,19 @@ public class DefaultServerWebExchange implements ServerWebExchange {
} }
// We will perform this validation... // We will perform this validation...
etag = padEtagIfNecessary(etag); etag = padEtagIfNecessary(etag);
for (String clientETag : ifNoneMatch) { if (etag.startsWith("W/")) {
etag = etag.substring(2);
}
for (String clientEtag : ifNoneMatch) {
// Compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3 // Compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3
if (StringUtils.hasLength(clientETag) && if (StringUtils.hasLength(clientEtag)) {
clientETag.replaceFirst("^W/", "").equals(etag.replaceFirst("^W/", ""))) { if (clientEtag.startsWith("W/")) {
this.notModified = true; clientEtag = clientEtag.substring(2);
break; }
if (clientEtag.equals(etag)) {
this.notModified = true;
break;
}
} }
} }
return true; return true;

7
spring-webmvc/src/main/java/org/springframework/web/servlet/tags/UrlTag.java

@ -38,7 +38,7 @@ import org.springframework.web.util.TagUtils;
import org.springframework.web.util.UriUtils; import org.springframework.web.util.UriUtils;
/** /**
* The {@code <url>} tag creates URLs. Modeled after the JSTL c:url tag with * The {@code <url>} tag creates URLs. Modeled after the JSTL {@code c:url} tag with
* backwards compatibility in mind. * backwards compatibility in mind.
* *
* <p>Enhancements to the JSTL functionality include: * <p>Enhancements to the JSTL functionality include:
@ -361,7 +361,8 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware {
usedParams.add(param.getName()); usedParams.add(param.getName());
String value = param.getValue(); String value = param.getValue();
try { try {
uri = uri.replace(template, (value != null ? UriUtils.encodePath(value, encoding) : "")); uri = StringUtils.replace(uri, template,
(value != null ? UriUtils.encodePath(value, encoding) : ""));
} }
catch (UnsupportedCharsetException ex) { catch (UnsupportedCharsetException ex) {
throw new JspException(ex); throw new JspException(ex);
@ -373,7 +374,7 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware {
usedParams.add(param.getName()); usedParams.add(param.getName());
String value = param.getValue(); String value = param.getValue();
try { try {
uri = uri.replace(template, uri = StringUtils.replace(uri, template,
(value != null ? UriUtils.encodePathSegment(param.getValue(), encoding) : "")); (value != null ? UriUtils.encodePathSegment(param.getValue(), encoding) : ""));
} }
catch (UnsupportedCharsetException ex) { catch (UnsupportedCharsetException ex) {

2
spring-webmvc/src/main/java/org/springframework/web/servlet/view/groovy/GroovyMarkupConfigurer.java

@ -194,7 +194,7 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration
protected URL resolveTemplate(ClassLoader classLoader, String templatePath) throws IOException { protected URL resolveTemplate(ClassLoader classLoader, String templatePath) throws IOException {
MarkupTemplateEngine.TemplateResource resource = MarkupTemplateEngine.TemplateResource.parse(templatePath); MarkupTemplateEngine.TemplateResource resource = MarkupTemplateEngine.TemplateResource.parse(templatePath);
Locale locale = LocaleContextHolder.getLocale(); Locale locale = LocaleContextHolder.getLocale();
URL url = classLoader.getResource(resource.withLocale(locale.toString().replace("-", "_")).toString()); URL url = classLoader.getResource(resource.withLocale(StringUtils.replace(locale.toString(), "-", "_")).toString());
if (url == null) { if (url == null) {
url = classLoader.getResource(resource.withLocale(locale.getLanguage()).toString()); url = classLoader.getResource(resource.withLocale(locale.getLanguage()).toString());
} }

5
spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/SockJsUrlInfo.java

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import java.util.UUID;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.IdGenerator; import org.springframework.util.IdGenerator;
import org.springframework.util.JdkIdGenerator; import org.springframework.util.JdkIdGenerator;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.sockjs.transport.TransportType; import org.springframework.web.socket.sockjs.transport.TransportType;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
@ -68,7 +69,7 @@ public class SockJsUrlInfo {
public String getSessionId() { public String getSessionId() {
if (this.sessionId == null) { if (this.sessionId == null) {
this.sessionId = getUuid().toString().replace("-",""); this.sessionId = StringUtils.delete(getUuid().toString(), "-");
} }
return this.sessionId; return this.sessionId;
} }

5
spring-websocket/src/main/java/org/springframework/web/socket/sockjs/frame/SockJsFrame.java

@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/** /**
* Represents a SockJS frame. Provides factory methods to create SockJS frames. * Represents a SockJS frame. Provides factory methods to create SockJS frames.
@ -142,7 +143,9 @@ public class SockJsFrame {
if (result.length() > 80) { if (result.length() > 80) {
result = result.substring(0, 80) + "...(truncated)"; result = result.substring(0, 80) + "...(truncated)";
} }
return "SockJsFrame content='" + result.replace("\n", "\\n").replace("\r", "\\r") + "'"; result = StringUtils.replace(result, "\n", "\\n");
result = StringUtils.replace(result, "\r", "\\r");
return "SockJsFrame content='" + result + "'";
} }

Loading…
Cancel
Save