Skip to content

Commit 3466330

Browse files
committed
Avoid regex pattern matching for simple String replacement steps
Issue: SPR-17279
1 parent cc87fbc commit 3466330

File tree

13 files changed

+61
-30
lines changed

13 files changed

+61
-30
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -183,7 +183,7 @@ public DateTimeFormatter createDateTimeFormatter(DateTimeFormatter fallbackForma
183183
// Using strict parsing to align with Joda-Time and standard DateFormat behavior:
184184
// otherwise, an overflow like e.g. Feb 29 for a non-leap-year wouldn't get rejected.
185185
// However, with strict parsing, a year digit needs to be specified as 'u'...
186-
String patternToUse = this.pattern.replace("yy", "uu");
186+
String patternToUse = StringUtils.replace(this.pattern, "yy", "uu");
187187
dateTimeFormatter = DateTimeFormatter.ofPattern(patternToUse).withResolverStyle(ResolverStyle.STRICT);
188188
}
189189
else if (this.iso != null && this.iso != ISO.NONE) {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424

2525
import org.springframework.lang.Nullable;
2626
import org.springframework.util.Assert;
27+
import org.springframework.util.StringUtils;
2728

2829
/**
2930
* ClassFileTransformer-based weaver, allowing for a list of transformers to be
@@ -73,7 +74,7 @@ public void addTransformer(ClassFileTransformer transformer) {
7374
* @return (possibly transformed) class byte definition
7475
*/
7576
public byte[] transformIfNecessary(String className, byte[] bytes) {
76-
String internalName = className.replace(".", "/");
77+
String internalName = StringUtils.replace(className, ".", "/");
7778
return transformIfNecessary(className, internalName, bytes, null);
7879
}
7980

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.asm.MethodVisitor;
2020
import org.springframework.expression.TypedValue;
2121
import org.springframework.expression.spel.CodeFlow;
22+
import org.springframework.util.StringUtils;
2223

2324
/**
2425
* Expression language AST node that represents a string literal.
@@ -33,9 +34,13 @@ public class StringLiteral extends Literal {
3334

3435

3536
public StringLiteral(String payload, int pos, String value) {
36-
super(payload,pos);
37-
value = value.substring(1, value.length() - 1);
38-
this.value = new TypedValue(value.replaceAll("''", "'").replaceAll("\"\"", "\""));
37+
super(payload, pos);
38+
39+
String valueWithinQuotes = value.substring(1, value.length() - 1);
40+
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "''", "'");
41+
valueWithinQuotes = StringUtils.replace(valueWithinQuotes, "\"\"", "\"");
42+
43+
this.value = new TypedValue(valueWithinQuotes);
3944
this.exitTypeDescriptor = "Ljava/lang/String";
4045
}
4146

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.util.ClassUtils;
3737
import org.springframework.util.ConcurrentReferenceHashMap;
3838
import org.springframework.util.ReflectionUtils;
39+
import org.springframework.util.StringUtils;
3940

4041
/**
4142
* A SpelCompiler will take a regular parsed expression and create (and load) a class
@@ -132,9 +133,9 @@ private int getNextSuffix() {
132133
@Nullable
133134
private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl expressionToCompile) {
134135
// Create class outline 'spel/ExNNN extends org.springframework.expression.spel.CompiledExpression'
135-
String clazzName = "spel/Ex" + getNextSuffix();
136+
String className = "spel/Ex" + getNextSuffix();
136137
ClassWriter cw = new ExpressionClassWriter();
137-
cw.visit(V1_5, ACC_PUBLIC, clazzName, null, "org/springframework/expression/spel/CompiledExpression", null);
138+
cw.visit(V1_5, ACC_PUBLIC, className, null, "org/springframework/expression/spel/CompiledExpression", null);
138139

139140
// Create default constructor
140141
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
@@ -152,7 +153,7 @@ private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl e
152153
new String[ ]{"org/springframework/expression/EvaluationException"});
153154
mv.visitCode();
154155

155-
CodeFlow cf = new CodeFlow(clazzName, cw);
156+
CodeFlow cf = new CodeFlow(className, cw);
156157

157158
// Ask the expression AST to generate the body of the method
158159
try {
@@ -181,7 +182,7 @@ private Class<? extends CompiledExpression> createExpressionClass(SpelNodeImpl e
181182
byte[] data = cw.toByteArray();
182183
// TODO need to make this conditionally occur based on a debug flag
183184
// dump(expressionToCompile.toStringAST(), clazzName, data);
184-
return loadClass(clazzName.replaceAll("/", "."), data);
185+
return loadClass(StringUtils.replace(className, "/", "."), data);
185186
}
186187

187188
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
292292

293293
for (int index = 1; index <= columnCount; index++) {
294294
String column = JdbcUtils.lookupColumnName(rsmd, index);
295-
String field = lowerCaseName(column.replaceAll(" ", ""));
295+
String field = lowerCaseName(StringUtils.delete(column, " "));
296296
PropertyDescriptor pd = (this.mappedFields != null ? this.mappedFields.get(field) : null);
297297
if (pd != null) {
298298
try {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.http.server.reactive.ServerHttpResponse;
3939
import org.springframework.lang.Nullable;
4040
import org.springframework.util.Assert;
41+
import org.springframework.util.StringUtils;
4142

4243
/**
4344
* {@code HttpMessageWriter} for {@code "text/event-stream"} responses.
@@ -135,7 +136,7 @@ private Flux<Publisher<DataBuffer>> encode(Publisher<?> input, ResolvableType el
135136
writeField("retry", retry.toMillis(), sb);
136137
}
137138
if (comment != null) {
138-
sb.append(':').append(comment.replaceAll("\\n", "\n:")).append("\n");
139+
sb.append(':').append(StringUtils.replace(comment, "\n", "\n:")).append("\n");
139140
}
140141
if (data != null) {
141142
sb.append("data:");
@@ -164,7 +165,7 @@ private <T> Flux<DataBuffer> encodeData(@Nullable T data, ResolvableType valueTy
164165

165166
if (data instanceof String) {
166167
String text = (String) data;
167-
return Flux.from(encodeText(text.replaceAll("\\n", "\ndata:") + "\n", mediaType, factory));
168+
return Flux.from(encodeText(StringUtils.replace(text, "\n", "\ndata:") + "\n", mediaType, factory));
168169
}
169170

170171
if (this.encoder == null) {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,15 @@ private boolean validateIfNoneMatch(@Nullable String etag) {
287287

288288
// We will perform this validation...
289289
etag = padEtagIfNecessary(etag);
290+
if (etag.startsWith("W/")) {
291+
etag = etag.substring(2);
292+
}
290293
while (ifNoneMatch.hasMoreElements()) {
291294
String clientETags = ifNoneMatch.nextElement();
292295
Matcher etagMatcher = ETAG_HEADER_VALUE_PATTERN.matcher(clientETags);
293296
// Compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3
294297
while (etagMatcher.find()) {
295-
if (StringUtils.hasLength(etagMatcher.group()) &&
296-
etag.replaceFirst("^W/", "").equals(etagMatcher.group(3))) {
298+
if (StringUtils.hasLength(etagMatcher.group()) && etag.equals(etagMatcher.group(3))) {
297299
this.notModified = true;
298300
break;
299301
}

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,7 @@ else if (isEligibleForEtag(request, responseWrapper, statusCode, responseWrapper
126126
String responseETag = generateETagHeaderValue(responseWrapper.getContentInputStream(), this.writeWeakETag);
127127
rawResponse.setHeader(HEADER_ETAG, responseETag);
128128
String requestETag = request.getHeader(HEADER_IF_NONE_MATCH);
129-
if (requestETag != null && ("*".equals(requestETag) || responseETag.equals(requestETag) ||
130-
responseETag.replaceFirst("^W/", "").equals(requestETag.replaceFirst("^W/", "")))) {
129+
if (requestETag != null && ("*".equals(requestETag) || compareETagHeaderValue(requestETag, responseETag))) {
131130
rawResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
132131
}
133132
else {
@@ -184,6 +183,16 @@ protected String generateETagHeaderValue(InputStream inputStream, boolean isWeak
184183
return builder.toString();
185184
}
186185

186+
private boolean compareETagHeaderValue(String requestETag, String responseETag) {
187+
if (requestETag.startsWith("W/")) {
188+
requestETag = requestETag.substring(2);
189+
}
190+
if (responseETag.startsWith("W/")) {
191+
responseETag = responseETag.substring(2);
192+
}
193+
return requestETag.equals(responseETag);
194+
}
195+
187196

188197
/**
189198
* This method can be used to disable the content caching response wrapper

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,12 +318,19 @@ private boolean validateIfNoneMatch(@Nullable String etag) {
318318
}
319319
// We will perform this validation...
320320
etag = padEtagIfNecessary(etag);
321-
for (String clientETag : ifNoneMatch) {
321+
if (etag.startsWith("W/")) {
322+
etag = etag.substring(2);
323+
}
324+
for (String clientEtag : ifNoneMatch) {
322325
// Compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3
323-
if (StringUtils.hasLength(clientETag) &&
324-
clientETag.replaceFirst("^W/", "").equals(etag.replaceFirst("^W/", ""))) {
325-
this.notModified = true;
326-
break;
326+
if (StringUtils.hasLength(clientEtag)) {
327+
if (clientEtag.startsWith("W/")) {
328+
clientEtag = clientEtag.substring(2);
329+
}
330+
if (clientEtag.equals(etag)) {
331+
this.notModified = true;
332+
break;
333+
}
327334
}
328335
}
329336
return true;

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
import org.springframework.web.util.UriUtils;
3939

4040
/**
41-
* The {@code <url>} tag creates URLs. Modeled after the JSTL c:url tag with
41+
* The {@code <url>} tag creates URLs. Modeled after the JSTL {@code c:url} tag with
4242
* backwards compatibility in mind.
4343
*
4444
* <p>Enhancements to the JSTL functionality include:
@@ -361,7 +361,8 @@ protected String replaceUriTemplateParams(String uri, List<Param> params, Set<St
361361
usedParams.add(param.getName());
362362
String value = param.getValue();
363363
try {
364-
uri = uri.replace(template, (value != null ? UriUtils.encodePath(value, encoding) : ""));
364+
uri = StringUtils.replace(uri, template,
365+
(value != null ? UriUtils.encodePath(value, encoding) : ""));
365366
}
366367
catch (UnsupportedCharsetException ex) {
367368
throw new JspException(ex);
@@ -373,7 +374,7 @@ protected String replaceUriTemplateParams(String uri, List<Param> params, Set<St
373374
usedParams.add(param.getName());
374375
String value = param.getValue();
375376
try {
376-
uri = uri.replace(template,
377+
uri = StringUtils.replace(uri, template,
377378
(value != null ? UriUtils.encodePathSegment(param.getValue(), encoding) : ""));
378379
}
379380
catch (UnsupportedCharsetException ex) {

0 commit comments

Comments
 (0)