Skip to content

Commit d707d38

Browse files
committed
Merge branch '5.1.x'
2 parents 849a848 + 28e206a commit d707d38

19 files changed

+286
-197
lines changed

spring-core/src/main/java/org/springframework/core/codec/AbstractDataBufferDecoder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -54,17 +54,17 @@ protected AbstractDataBufferDecoder(MimeType... supportedMimeTypes) {
5454

5555

5656
@Override
57-
public Flux<T> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
57+
public Flux<T> decode(Publisher<DataBuffer> input, ResolvableType elementType,
5858
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
5959

60-
return Flux.from(inputStream).map(buffer -> decodeDataBuffer(buffer, elementType, mimeType, hints));
60+
return Flux.from(input).map(buffer -> decodeDataBuffer(buffer, elementType, mimeType, hints));
6161
}
6262

6363
@Override
64-
public Mono<T> decodeToMono(Publisher<DataBuffer> inputStream, ResolvableType elementType,
64+
public Mono<T> decodeToMono(Publisher<DataBuffer> input, ResolvableType elementType,
6565
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
6666

67-
return DataBufferUtils.join(inputStream)
67+
return DataBufferUtils.join(input)
6868
.map(buffer -> decodeDataBuffer(buffer, elementType, mimeType, hints));
6969
}
7070

spring-core/src/main/java/org/springframework/core/codec/AbstractDecoder.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -78,7 +78,12 @@ public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType
7878
if (mimeType == null) {
7979
return true;
8080
}
81-
return this.decodableMimeTypes.stream().anyMatch(candidate -> candidate.isCompatibleWith(mimeType));
81+
for (MimeType candidate : this.decodableMimeTypes) {
82+
if (candidate.isCompatibleWith(mimeType)) {
83+
return true;
84+
}
85+
}
86+
return false;
8287
}
8388

8489
@Override

spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType
7474
if (mimeType == null) {
7575
return true;
7676
}
77-
for(MimeType candidate : this.encodableMimeTypes) {
77+
for (MimeType candidate : this.encodableMimeTypes) {
7878
if (candidate.isCompatibleWith(mimeType)) {
7979
return true;
8080
}

spring-core/src/main/java/org/springframework/core/codec/DataBufferDecoder.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType
5757
}
5858

5959
@Override
60-
public Flux<DataBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
60+
public Flux<DataBuffer> decode(Publisher<DataBuffer> input, ResolvableType elementType,
6161
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
6262

63-
return Flux.from(inputStream);
63+
return Flux.from(input);
6464
}
6565

6666
@Override

spring-core/src/main/java/org/springframework/core/codec/ResourceEncoder.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -65,15 +65,14 @@ public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType
6565
}
6666

6767
@Override
68-
protected Flux<DataBuffer> encode(Resource resource, DataBufferFactory dataBufferFactory,
68+
protected Flux<DataBuffer> encode(Resource resource, DataBufferFactory bufferFactory,
6969
ResolvableType type, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
7070

7171
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
7272
String logPrefix = Hints.getLogPrefix(hints);
7373
logger.debug(logPrefix + "Writing [" + resource + "]");
7474
}
75-
76-
return DataBufferUtils.read(resource, dataBufferFactory, this.bufferSize);
75+
return DataBufferUtils.read(resource, bufferFactory, this.bufferSize);
7776
}
7877

7978
}

spring-core/src/main/java/org/springframework/core/codec/ResourceRegionEncoder.java

+23-30
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -76,16 +76,16 @@ public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType
7676
}
7777

7878
@Override
79-
public Flux<DataBuffer> encode(Publisher<? extends ResourceRegion> inputStream,
79+
public Flux<DataBuffer> encode(Publisher<? extends ResourceRegion> input,
8080
DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType,
8181
@Nullable Map<String, Object> hints) {
8282

83-
Assert.notNull(inputStream, "'inputStream' must not be null");
83+
Assert.notNull(input, "'inputStream' must not be null");
8484
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
8585
Assert.notNull(elementType, "'elementType' must not be null");
8686

87-
if (inputStream instanceof Mono) {
88-
return Mono.from(inputStream)
87+
if (input instanceof Mono) {
88+
return Mono.from(input)
8989
.flatMapMany(region -> {
9090
if (!region.getResource().isReadable()) {
9191
return Flux.error(new EncodingException(
@@ -96,32 +96,25 @@ public Flux<DataBuffer> encode(Publisher<? extends ResourceRegion> inputStream,
9696
}
9797
else {
9898
final String boundaryString = Hints.getRequiredHint(hints, BOUNDARY_STRING_HINT);
99-
byte[] startBoundary = getAsciiBytes("\r\n--" + boundaryString + "\r\n");
100-
byte[] contentType = mimeType != null ? getAsciiBytes("Content-Type: " + mimeType + "\r\n") : new byte[0];
99+
byte[] startBoundary = toAsciiBytes("\r\n--" + boundaryString + "\r\n");
100+
byte[] contentType = mimeType != null ? toAsciiBytes("Content-Type: " + mimeType + "\r\n") : new byte[0];
101101

102-
return Flux.from(inputStream).
103-
concatMap(region -> {
102+
return Flux.from(input)
103+
.concatMap(region -> {
104104
if (!region.getResource().isReadable()) {
105105
return Flux.error(new EncodingException(
106106
"Resource " + region.getResource() + " is not readable"));
107107
}
108-
else {
109-
return Flux.concat(
110-
getRegionPrefix(bufferFactory, startBoundary, contentType, region),
111-
writeResourceRegion(region, bufferFactory, hints));
112-
}
108+
Flux<DataBuffer> prefix = Flux.just(
109+
bufferFactory.wrap(startBoundary),
110+
bufferFactory.wrap(contentType),
111+
bufferFactory.wrap(getContentRangeHeader(region))); // only wrapping, no allocation
112+
113+
return prefix.concatWith(writeResourceRegion(region, bufferFactory, hints));
113114
})
114-
.concatWith(getRegionSuffix(bufferFactory, boundaryString));
115+
.concatWithValues(getRegionSuffix(bufferFactory, boundaryString));
115116
}
116-
}
117-
118-
private Flux<DataBuffer> getRegionPrefix(DataBufferFactory bufferFactory, byte[] startBoundary,
119-
byte[] contentType, ResourceRegion region) {
120-
121-
return Flux.just(
122-
bufferFactory.wrap(startBoundary),
123-
bufferFactory.wrap(contentType),
124-
bufferFactory.wrap(getContentRangeHeader(region))); // only wrapping, no allocation
117+
// No doOnDiscard (no caching after DataBufferUtils#read)
125118
}
126119

127120
private Flux<DataBuffer> writeResourceRegion(
@@ -140,12 +133,12 @@ private Flux<DataBuffer> writeResourceRegion(
140133
return DataBufferUtils.takeUntilByteCount(in, count);
141134
}
142135

143-
private Flux<DataBuffer> getRegionSuffix(DataBufferFactory bufferFactory, String boundaryString) {
144-
byte[] endBoundary = getAsciiBytes("\r\n--" + boundaryString + "--");
145-
return Flux.just(bufferFactory.wrap(endBoundary));
136+
private DataBuffer getRegionSuffix(DataBufferFactory bufferFactory, String boundaryString) {
137+
byte[] endBoundary = toAsciiBytes("\r\n--" + boundaryString + "--");
138+
return bufferFactory.wrap(endBoundary);
146139
}
147140

148-
private byte[] getAsciiBytes(String in) {
141+
private byte[] toAsciiBytes(String in) {
149142
return in.getBytes(StandardCharsets.US_ASCII);
150143
}
151144

@@ -155,10 +148,10 @@ private byte[] getContentRangeHeader(ResourceRegion region) {
155148
OptionalLong contentLength = contentLength(region.getResource());
156149
if (contentLength.isPresent()) {
157150
long length = contentLength.getAsLong();
158-
return getAsciiBytes("Content-Range: bytes " + start + '-' + end + '/' + length + "\r\n\r\n");
151+
return toAsciiBytes("Content-Range: bytes " + start + '-' + end + '/' + length + "\r\n\r\n");
159152
}
160153
else {
161-
return getAsciiBytes("Content-Range: bytes " + start + '-' + end + "\r\n\r\n");
154+
return toAsciiBytes("Content-Range: bytes " + start + '-' + end + "\r\n\r\n");
162155
}
163156
}
164157

spring-core/src/main/java/org/springframework/core/codec/StringDecoder.java

+55-53
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -25,7 +25,6 @@
2525
import java.util.Map;
2626
import java.util.concurrent.ConcurrentHashMap;
2727
import java.util.concurrent.ConcurrentMap;
28-
import java.util.stream.Collectors;
2928

3029
import org.reactivestreams.Publisher;
3130
import reactor.core.publisher.Flux;
@@ -88,111 +87,114 @@ public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType
8887
}
8988

9089
@Override
91-
public Flux<String> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType,
90+
public Flux<String> decode(Publisher<DataBuffer> input, ResolvableType elementType,
9291
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
9392

9493
List<byte[]> delimiterBytes = getDelimiterBytes(mimeType);
9594

96-
Flux<DataBuffer> inputFlux = Flux.from(inputStream)
97-
.flatMapIterable(dataBuffer -> splitOnDelimiter(dataBuffer, delimiterBytes))
98-
.bufferUntil(StringDecoder::isEndFrame)
95+
Flux<DataBuffer> inputFlux = Flux.from(input)
96+
.flatMapIterable(buffer -> splitOnDelimiter(buffer, delimiterBytes))
97+
.bufferUntil(buffer -> buffer == END_FRAME)
9998
.map(StringDecoder::joinUntilEndFrame)
10099
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release);
101100

102101
return super.decode(inputFlux, elementType, mimeType, hints);
103102
}
104103

105104
private List<byte[]> getDelimiterBytes(@Nullable MimeType mimeType) {
106-
return this.delimitersCache.computeIfAbsent(getCharset(mimeType),
107-
charset -> this.delimiters.stream()
108-
.map(s -> s.getBytes(charset))
109-
.collect(Collectors.toList()));
105+
return this.delimitersCache.computeIfAbsent(getCharset(mimeType), charset -> {
106+
List<byte[]> list = new ArrayList<>();
107+
for (String delimiter : this.delimiters) {
108+
byte[] bytes = delimiter.getBytes(charset);
109+
list.add(bytes);
110+
}
111+
return list;
112+
});
110113
}
111114

112115
/**
113116
* Split the given data buffer on delimiter boundaries.
114117
* The returned Flux contains an {@link #END_FRAME} buffer after each delimiter.
115118
*/
116-
private List<DataBuffer> splitOnDelimiter(DataBuffer dataBuffer, List<byte[]> delimiterBytes) {
119+
private List<DataBuffer> splitOnDelimiter(DataBuffer buffer, List<byte[]> delimiterBytes) {
117120
List<DataBuffer> frames = new ArrayList<>();
118-
do {
119-
int length = Integer.MAX_VALUE;
120-
byte[] matchingDelimiter = null;
121-
for (byte[] delimiter : delimiterBytes) {
122-
int index = indexOf(dataBuffer, delimiter);
123-
if (index >= 0 && index < length) {
124-
length = index;
125-
matchingDelimiter = delimiter;
121+
try {
122+
do {
123+
int length = Integer.MAX_VALUE;
124+
byte[] matchingDelimiter = null;
125+
for (byte[] delimiter : delimiterBytes) {
126+
int index = indexOf(buffer, delimiter);
127+
if (index >= 0 && index < length) {
128+
length = index;
129+
matchingDelimiter = delimiter;
130+
}
126131
}
127-
}
128-
DataBuffer frame;
129-
int readPosition = dataBuffer.readPosition();
130-
if (matchingDelimiter != null) {
131-
if (this.stripDelimiter) {
132-
frame = dataBuffer.slice(readPosition, length);
132+
DataBuffer frame;
133+
int readPosition = buffer.readPosition();
134+
if (matchingDelimiter != null) {
135+
frame = this.stripDelimiter ?
136+
buffer.slice(readPosition, length) :
137+
buffer.slice(readPosition, length + matchingDelimiter.length);
138+
buffer.readPosition(readPosition + length + matchingDelimiter.length);
139+
frames.add(DataBufferUtils.retain(frame));
140+
frames.add(END_FRAME);
133141
}
134142
else {
135-
frame = dataBuffer.slice(readPosition, length + matchingDelimiter.length);
143+
frame = buffer.slice(readPosition, buffer.readableByteCount());
144+
buffer.readPosition(readPosition + buffer.readableByteCount());
145+
frames.add(DataBufferUtils.retain(frame));
136146
}
137-
dataBuffer.readPosition(readPosition + length + matchingDelimiter.length);
138-
139-
frames.add(DataBufferUtils.retain(frame));
140-
frames.add(END_FRAME);
141147
}
142-
else {
143-
frame = dataBuffer.slice(readPosition, dataBuffer.readableByteCount());
144-
dataBuffer.readPosition(readPosition + dataBuffer.readableByteCount());
145-
frames.add(DataBufferUtils.retain(frame));
148+
while (buffer.readableByteCount() > 0);
149+
}
150+
catch (Throwable ex) {
151+
for (DataBuffer frame : frames) {
152+
DataBufferUtils.release(frame);
146153
}
154+
throw ex;
155+
}
156+
finally {
157+
DataBufferUtils.release(buffer);
147158
}
148-
while (dataBuffer.readableByteCount() > 0);
149-
150-
DataBufferUtils.release(dataBuffer);
151159
return frames;
152160
}
153161

154162
/**
155163
* Find the given delimiter in the given data buffer.
156164
* @return the index of the delimiter, or -1 if not found.
157165
*/
158-
private static int indexOf(DataBuffer dataBuffer, byte[] delimiter) {
159-
for (int i = dataBuffer.readPosition(); i < dataBuffer.writePosition(); i++) {
160-
int dataBufferPos = i;
166+
private static int indexOf(DataBuffer buffer, byte[] delimiter) {
167+
for (int i = buffer.readPosition(); i < buffer.writePosition(); i++) {
168+
int bufferPos = i;
161169
int delimiterPos = 0;
162170
while (delimiterPos < delimiter.length) {
163-
if (dataBuffer.getByte(dataBufferPos) != delimiter[delimiterPos]) {
171+
if (buffer.getByte(bufferPos) != delimiter[delimiterPos]) {
164172
break;
165173
}
166174
else {
167-
dataBufferPos++;
168-
if (dataBufferPos == dataBuffer.writePosition() &&
169-
delimiterPos != delimiter.length - 1) {
175+
bufferPos++;
176+
boolean endOfBuffer = bufferPos == buffer.writePosition();
177+
boolean endOfDelimiter = delimiterPos == delimiter.length - 1;
178+
if (endOfBuffer && !endOfDelimiter) {
170179
return -1;
171180
}
172181
}
173182
delimiterPos++;
174183
}
175184
if (delimiterPos == delimiter.length) {
176-
return i - dataBuffer.readPosition();
185+
return i - buffer.readPosition();
177186
}
178187
}
179188
return -1;
180189
}
181190

182-
/**
183-
* Check whether the given buffer is {@link #END_FRAME}.
184-
*/
185-
private static boolean isEndFrame(DataBuffer dataBuffer) {
186-
return dataBuffer == END_FRAME;
187-
}
188-
189191
/**
190192
* Join the given list of buffers into a single buffer.
191193
*/
192194
private static DataBuffer joinUntilEndFrame(List<DataBuffer> dataBuffers) {
193195
if (!dataBuffers.isEmpty()) {
194196
int lastIdx = dataBuffers.size() - 1;
195-
if (isEndFrame(dataBuffers.get(lastIdx))) {
197+
if (dataBuffers.get(lastIdx) == END_FRAME) {
196198
dataBuffers.remove(lastIdx);
197199
}
198200
}

0 commit comments

Comments
 (0)