001/*
002 * Copyright 2002-2018 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.http.codec.json;
018
019import java.util.Collections;
020import java.util.List;
021import java.util.Map;
022
023import com.fasterxml.jackson.core.PrettyPrinter;
024import com.fasterxml.jackson.core.util.DefaultIndenter;
025import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
026import com.fasterxml.jackson.databind.ObjectMapper;
027import com.fasterxml.jackson.databind.ObjectWriter;
028import com.fasterxml.jackson.databind.SerializationFeature;
029import reactor.core.publisher.Flux;
030
031import org.springframework.core.ResolvableType;
032import org.springframework.http.MediaType;
033import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
034import org.springframework.lang.Nullable;
035import org.springframework.util.MimeType;
036
037/**
038 * Encode from an {@code Object} stream to a byte stream of JSON objects using Jackson 2.9.
039 * For non-streaming use cases, {@link Flux} elements are collected into a {@link List}
040 * before serialization for performance reason.
041 *
042 * @author Sebastien Deleuze
043 * @author Arjen Poutsma
044 * @since 5.0
045 * @see Jackson2JsonDecoder
046 */
047public class Jackson2JsonEncoder extends AbstractJackson2Encoder {
048
049        @Nullable
050        private final PrettyPrinter ssePrettyPrinter;
051
052
053        public Jackson2JsonEncoder() {
054                this(Jackson2ObjectMapperBuilder.json().build());
055        }
056
057        public Jackson2JsonEncoder(ObjectMapper mapper, MimeType... mimeTypes) {
058                super(mapper, mimeTypes);
059                setStreamingMediaTypes(Collections.singletonList(MediaType.APPLICATION_STREAM_JSON));
060                this.ssePrettyPrinter = initSsePrettyPrinter();
061        }
062
063        private static PrettyPrinter initSsePrettyPrinter() {
064                DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
065                printer.indentObjectsWith(new DefaultIndenter("  ", "\ndata:"));
066                return printer;
067        }
068
069
070        @Override
071        protected ObjectWriter customizeWriter(ObjectWriter writer, @Nullable MimeType mimeType,
072                        ResolvableType elementType, @Nullable Map<String, Object> hints) {
073
074                return (this.ssePrettyPrinter != null &&
075                                MediaType.TEXT_EVENT_STREAM.isCompatibleWith(mimeType) &&
076                                writer.getConfig().isEnabled(SerializationFeature.INDENT_OUTPUT) ?
077                                writer.with(this.ssePrettyPrinter) : writer);
078        }
079
080}