001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.core.codec;
018
019import java.util.Map;
020
021import org.reactivestreams.Publisher;
022import reactor.core.publisher.Flux;
023import reactor.core.publisher.Mono;
024
025import org.springframework.core.ResolvableType;
026import org.springframework.core.io.buffer.DataBuffer;
027import org.springframework.core.io.buffer.DataBufferUtils;
028import org.springframework.lang.Nullable;
029import org.springframework.util.MimeType;
030
031/**
032 * Abstract base class for {@code Decoder} implementations that can decode
033 * a {@code DataBuffer} directly to the target element type.
034 *
035 * <p>Sub-classes must implement {@link #decodeDataBuffer} to provide a way to
036 * transform a {@code DataBuffer} to the target data type. The default
037 * {@link #decode} implementation transforms each individual data buffer while
038 * {@link #decodeToMono} applies "reduce" and transforms the aggregated buffer.
039 *
040 * <p>Sub-classes can override {@link #decode} in order to split the input stream
041 * along different boundaries (e.g. on new line characters for {@code String})
042 * or always reduce to a single data buffer (e.g. {@code Resource}).
043 *
044 * @author Rossen Stoyanchev
045 * @since 5.0
046 * @param <T> the element type
047 */
048@SuppressWarnings("deprecation")
049public abstract class AbstractDataBufferDecoder<T> extends AbstractDecoder<T> {
050
051        private int maxInMemorySize = 256 * 1024;
052
053
054        protected AbstractDataBufferDecoder(MimeType... supportedMimeTypes) {
055                super(supportedMimeTypes);
056        }
057
058
059        /**
060         * Configure a limit on the number of bytes that can be buffered whenever
061         * the input stream needs to be aggregated. This can be a result of
062         * decoding to a single {@code DataBuffer},
063         * {@link java.nio.ByteBuffer ByteBuffer}, {@code byte[]},
064         * {@link org.springframework.core.io.Resource Resource}, {@code String}, etc.
065         * It can also occur when splitting the input stream, e.g. delimited text,
066         * in which case the limit applies to data buffered between delimiters.
067         * <p>By default this is set to 256K.
068         * @param byteCount the max number of bytes to buffer, or -1 for unlimited
069         * @since 5.1.11
070         */
071        public void setMaxInMemorySize(int byteCount) {
072                this.maxInMemorySize = byteCount;
073        }
074
075        /**
076         * Return the {@link #setMaxInMemorySize configured} byte count limit.
077         * @since 5.1.11
078         */
079        public int getMaxInMemorySize() {
080                return this.maxInMemorySize;
081        }
082
083
084        @Override
085        public Flux<T> decode(Publisher<DataBuffer> input, ResolvableType elementType,
086                        @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
087
088                return Flux.from(input).map(buffer -> decodeDataBuffer(buffer, elementType, mimeType, hints));
089        }
090
091        @Override
092        public Mono<T> decodeToMono(Publisher<DataBuffer> input, ResolvableType elementType,
093                        @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
094
095                return DataBufferUtils.join(input, this.maxInMemorySize)
096                                .map(buffer -> decodeDataBuffer(buffer, elementType, mimeType, hints));
097        }
098
099        /**
100         * How to decode a {@code DataBuffer} to the target element type.
101         * @deprecated as of 5.2, please implement
102         * {@link #decode(DataBuffer, ResolvableType, MimeType, Map)} instead
103         */
104        @Deprecated
105        @Nullable
106        protected T decodeDataBuffer(DataBuffer buffer, ResolvableType elementType,
107                        @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
108
109                return decode(buffer, elementType, mimeType, hints);
110        }
111
112}