All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.web.reactive.result.view.HttpMessageWriterView Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.reactive.result.view;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;

import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Encoder;
import org.springframework.core.codec.Hints;
import org.springframework.http.MediaType;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;

/**
 * {@code View} that writes model attribute(s) with an {@link HttpMessageWriter}.
 *
 * @author Rossen Stoyanchev
 * @since 5.0
 */
public class HttpMessageWriterView implements View {

	private final HttpMessageWriter writer;

	private final Set modelKeys = new HashSet<>(4);

	private final boolean canWriteMap;


	/**
	 * Constructor with an {@code Encoder}.
	 */
	public HttpMessageWriterView(Encoder encoder) {
		this(new EncoderHttpMessageWriter<>(encoder));
	}

	/**
	 * Constructor with a fully initialized {@link HttpMessageWriter}.
	 */
	public HttpMessageWriterView(HttpMessageWriter writer) {
		Assert.notNull(writer, "HttpMessageWriter is required");
		this.writer = writer;
		this.canWriteMap = writer.canWrite(ResolvableType.forClass(Map.class), null);
	}


	/**
	 * Return the configured message writer.
	 */
	public HttpMessageWriter getMessageWriter() {
		return this.writer;
	}

	/**
	 * {@inheritDoc}
	 * 

The implementation of this method for {@link HttpMessageWriterView} * delegates to {@link HttpMessageWriter#getWritableMediaTypes()}. */ @Override public List getSupportedMediaTypes() { return this.writer.getWritableMediaTypes(); } /** * Set the attributes in the model that should be rendered by this view. * When set, all other model attributes will be ignored. The matching * attributes are further narrowed with {@link HttpMessageWriter#canWrite}. * The matching attributes are processed as follows: *

    *
  • 0: nothing is written to the response body. *
  • 1: the matching attribute is passed to the writer. *
  • 2..N: if the writer supports {@link Map}, write all matches; * otherwise raise an {@link IllegalStateException}. *
*/ public void setModelKeys(@Nullable Set modelKeys) { this.modelKeys.clear(); if (modelKeys != null) { this.modelKeys.addAll(modelKeys); } } /** * Return the configured model keys. */ public final Set getModelKeys() { return this.modelKeys; } @Override @SuppressWarnings("unchecked") public Mono render( @Nullable Map model, @Nullable MediaType contentType, ServerWebExchange exchange) { Object value = getObjectToRender(model); return (value != null ? write(value, contentType, exchange) : exchange.getResponse().setComplete()); } @Nullable private Object getObjectToRender(@Nullable Map model) { if (model == null) { return null; } Map result = model.entrySet().stream() .filter(this::isMatch) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); if (result.isEmpty()) { return null; } else if (result.size() == 1) { return result.values().iterator().next(); } else if (this.canWriteMap) { return result; } else { throw new IllegalStateException("Multiple matches found: " + result + " but " + "Map rendering is not supported by " + getMessageWriter().getClass().getName()); } } private boolean isMatch(Map.Entry entry) { if (entry.getValue() == null) { return false; } if (!getModelKeys().isEmpty() && !getModelKeys().contains(entry.getKey())) { return false; } ResolvableType type = ResolvableType.forInstance(entry.getValue()); return getMessageWriter().canWrite(type, null); } @SuppressWarnings("unchecked") private Mono write(T value, @Nullable MediaType contentType, ServerWebExchange exchange) { Publisher input = Mono.justOrEmpty(value); ResolvableType elementType = ResolvableType.forClass(value.getClass()); return ((HttpMessageWriter) this.writer).write( input, elementType, contentType, exchange.getResponse(), Hints.from(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix())); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy