Introduce ServerHttp[Encoder|Decoder]
ServerHttpEncoder and ServerHttpDecoder are HTTP-specific specializations that can prepare encoding and decoding hints from extra information available on the server side. As a result Jackson2ServerHttpMessageReader is no longer needed.
This commit is contained in:
@@ -34,7 +34,11 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of {@code HttpMessageReader} delegating to a {@link Decoder}.
|
* {@code HttpMessageReader} that wraps and delegates to a {@link Decoder}.
|
||||||
|
*
|
||||||
|
* <p>Also a {@code ServerHttpMessageReader} that pre-resolves decoding hints
|
||||||
|
* from the extra information available on the server side such as the request
|
||||||
|
* or controller method parameter annotations.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
@@ -105,7 +109,7 @@ public class DecoderHttpMessageReader<T> implements ServerHttpMessageReader<T> {
|
|||||||
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
|
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
|
||||||
|
|
||||||
Map<String, Object> allHints = new HashMap<>(4);
|
Map<String, Object> allHints = new HashMap<>(4);
|
||||||
allHints.putAll(resolveReadHints(streamType, elementType, request, response));
|
allHints.putAll(getReadHints(streamType, elementType, request, response));
|
||||||
allHints.putAll(hints);
|
allHints.putAll(hints);
|
||||||
|
|
||||||
return read(elementType, request, allHints);
|
return read(elementType, request, allHints);
|
||||||
@@ -116,19 +120,24 @@ public class DecoderHttpMessageReader<T> implements ServerHttpMessageReader<T> {
|
|||||||
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
|
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
|
||||||
|
|
||||||
Map<String, Object> allHints = new HashMap<>(4);
|
Map<String, Object> allHints = new HashMap<>(4);
|
||||||
allHints.putAll(resolveReadHints(streamType, elementType, request, response));
|
allHints.putAll(getReadHints(streamType, elementType, request, response));
|
||||||
allHints.putAll(hints);
|
allHints.putAll(hints);
|
||||||
|
|
||||||
return readMono(elementType, request, allHints);
|
return readMono(elementType, request, allHints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve hints to pass to the decoder, e.g. by checking for annotations
|
* Get additional hints for decoding for example based on the server request
|
||||||
* on a controller method parameter or checking the server request.
|
* or annotations from controller method parameters. By default, delegate to
|
||||||
|
* the decoder if it is an instance of {@link ServerHttpDecoder}.
|
||||||
*/
|
*/
|
||||||
protected Map<String, Object> resolveReadHints(ResolvableType streamType,
|
protected Map<String, Object> getReadHints(ResolvableType streamType,
|
||||||
ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response) {
|
ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||||
|
|
||||||
|
if (this.decoder instanceof ServerHttpDecoder) {
|
||||||
|
ServerHttpDecoder<?> httpDecoder = (ServerHttpDecoder<?>) this.decoder;
|
||||||
|
return httpDecoder.getDecodeHints(streamType, elementType, request, response);
|
||||||
|
}
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ import static org.springframework.core.codec.AbstractEncoder.FLUSHING_STRATEGY_H
|
|||||||
import static org.springframework.core.codec.AbstractEncoder.FlushingStrategy.AFTER_EACH_ELEMENT;
|
import static org.springframework.core.codec.AbstractEncoder.FlushingStrategy.AFTER_EACH_ELEMENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of {@code HttpMessageWriter} delegating to an {@link Encoder}.
|
* {@code HttpMessageWriter} that wraps and delegates to a {@link Encoder}.
|
||||||
|
*
|
||||||
|
* <p>Also a {@code ServerHttpMessageWriter} that pre-resolves encoding hints
|
||||||
|
* from the extra information available on the server side such as the request
|
||||||
|
* or controller method annotations.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
@@ -132,19 +136,24 @@ public class EncoderHttpMessageWriter<T> implements ServerHttpMessageWriter<T> {
|
|||||||
ServerHttpResponse response, Map<String, Object> hints) {
|
ServerHttpResponse response, Map<String, Object> hints) {
|
||||||
|
|
||||||
Map<String, Object> allHints = new HashMap<>();
|
Map<String, Object> allHints = new HashMap<>();
|
||||||
allHints.putAll(resolveWriteHints(streamType, elementType, mediaType, request, response));
|
allHints.putAll(getWriteHints(streamType, elementType, mediaType, request, response));
|
||||||
allHints.putAll(hints);
|
allHints.putAll(hints);
|
||||||
|
|
||||||
return write(inputStream, elementType, mediaType, response, allHints);
|
return write(inputStream, elementType, mediaType, response, allHints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve hints to pass to the encoder, e.g. by checking for annotations
|
* Get additional hints for encoding for example based on the server request
|
||||||
* on a controller method parameter or checking the server request.
|
* or annotations from controller method parameters. By default, delegate to
|
||||||
|
* the encoder if it is an instance of {@link ServerHttpEncoder}.
|
||||||
*/
|
*/
|
||||||
protected Map<String, Object> resolveWriteHints(ResolvableType streamType, ResolvableType elementType,
|
protected Map<String, Object> getWriteHints(ResolvableType streamType, ResolvableType elementType,
|
||||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||||
|
|
||||||
|
if (this.encoder instanceof ServerHttpEncoder) {
|
||||||
|
ServerHttpEncoder<?> httpEncoder = (ServerHttpEncoder<?>) this.encoder;
|
||||||
|
return httpEncoder.getEncodeHints(streamType, elementType, mediaType, request, response);
|
||||||
|
}
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2017 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
|
|
||||||
*
|
|
||||||
* http://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.http.codec;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
|
||||||
import org.springframework.core.ResolvableType;
|
|
||||||
import org.springframework.core.codec.Decoder;
|
|
||||||
import org.springframework.http.codec.json.AbstractJackson2Codec;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link ServerHttpMessageReader} that resolves those annotation or request based Jackson 2 hints:
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code @JsonView} + {@code @RequestBody} annotated handler method parameter</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @author Sebastien Deleuze
|
|
||||||
* @author Rossen Stoyanchev
|
|
||||||
* @since 5.0
|
|
||||||
* @see com.fasterxml.jackson.annotation.JsonView
|
|
||||||
*/
|
|
||||||
public class Jackson2ServerHttpMessageReader extends DecoderHttpMessageReader<Object> {
|
|
||||||
|
|
||||||
|
|
||||||
public Jackson2ServerHttpMessageReader(Decoder<Object> decoder) {
|
|
||||||
super(decoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Map<String, Object> resolveReadHints(ResolvableType streamType,
|
|
||||||
ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response) {
|
|
||||||
|
|
||||||
Object source = streamType.getSource();
|
|
||||||
MethodParameter parameter = (source instanceof MethodParameter ? (MethodParameter)source : null);
|
|
||||||
if (parameter != null) {
|
|
||||||
JsonView annotation = parameter.getParameterAnnotation(JsonView.class);
|
|
||||||
if (annotation != null) {
|
|
||||||
Class<?>[] classes = annotation.value();
|
|
||||||
if (classes.length != 1) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"@JsonView only supported for read hints with exactly 1 class argument: " + parameter);
|
|
||||||
}
|
|
||||||
return Collections.singletonMap(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -20,22 +20,20 @@ package org.springframework.http.codec;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import static org.springframework.core.codec.AbstractEncoder.FLUSHING_STRATEGY_HINT;
|
|
||||||
import static org.springframework.core.codec.AbstractEncoder.FlushingStrategy.AFTER_EACH_ELEMENT;
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.codec.AbstractEncoder;
|
import org.springframework.core.codec.AbstractEncoder;
|
||||||
import org.springframework.core.codec.Encoder;
|
import org.springframework.core.codec.Encoder;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||||
import org.springframework.http.codec.json.AbstractJackson2Codec;
|
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
|
||||||
|
import static org.springframework.core.codec.AbstractEncoder.FLUSHING_STRATEGY_HINT;
|
||||||
|
import static org.springframework.core.codec.AbstractEncoder.FlushingStrategy.AFTER_EACH_ELEMENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Jackson {@link ServerHttpMessageWriter} that resolves {@code @JsonView} annotated handler
|
* Jackson {@link ServerHttpMessageWriter} that resolves {@code @JsonView} annotated handler
|
||||||
* method and deals with {@link AbstractEncoder#FLUSHING_STRATEGY_HINT}.
|
* method and deals with {@link AbstractEncoder#FLUSHING_STRATEGY_HINT}.
|
||||||
@@ -76,25 +74,4 @@ public class Jackson2ServerHttpMessageWriter extends EncoderHttpMessageWriter<Ob
|
|||||||
return super.write(inputStream, streamType, elementType, mediaType, request, response, hints);
|
return super.write(inputStream, streamType, elementType, mediaType, request, response, hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Map<String, Object> resolveWriteHints(ResolvableType streamType, ResolvableType elementType,
|
|
||||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
|
||||||
|
|
||||||
Map<String, Object> hints = new HashMap<>();
|
|
||||||
Object source = streamType.getSource();
|
|
||||||
MethodParameter returnValue = (source instanceof MethodParameter ? (MethodParameter)source : null);
|
|
||||||
if (returnValue != null) {
|
|
||||||
JsonView annotation = returnValue.getMethodAnnotation(JsonView.class);
|
|
||||||
if (annotation != null) {
|
|
||||||
Class<?>[] classes = annotation.value();
|
|
||||||
if (classes.length != 1) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"@JsonView only supported for write hints with exactly 1 class argument: " + returnValue);
|
|
||||||
}
|
|
||||||
hints.put(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hints;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 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
|
||||||
|
*
|
||||||
|
* http://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.http.codec;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
|
import org.springframework.core.codec.Decoder;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code Decoder} extension for server-side decoding of the HTTP request body.
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public interface ServerHttpDecoder<T> extends Decoder<T> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get decoding hints based on the server request or annotations on the
|
||||||
|
* target controller method parameter.
|
||||||
|
*
|
||||||
|
* @param actualType the actual target type to decode to, possibly a reactive
|
||||||
|
* wrapper and sourced from {@link org.springframework.core.MethodParameter},
|
||||||
|
* i.e. providing access to method parameter annotations.
|
||||||
|
* @param elementType the element type within {@code Flux/Mono} that we're
|
||||||
|
* trying to decode to.
|
||||||
|
* @param request the current request
|
||||||
|
* @param response the current response
|
||||||
|
* @return a Map with hints, possibly empty
|
||||||
|
*/
|
||||||
|
Map<String, Object> getDecodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||||
|
ServerHttpRequest request, ServerHttpResponse response);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 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
|
||||||
|
*
|
||||||
|
* http://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.http.codec;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
|
import org.springframework.core.codec.Encoder;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code Encoder} extension for server-side encoding of the HTTP response body.
|
||||||
|
*
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
public interface ServerHttpEncoder<T> extends Encoder<T> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get decoding hints based on the server request or annotations on the
|
||||||
|
* target controller method parameter.
|
||||||
|
*
|
||||||
|
* @param actualType the actual source type to encode, possibly a reactive
|
||||||
|
* wrapper and sourced from {@link org.springframework.core.MethodParameter},
|
||||||
|
* i.e. providing access to method annotations.
|
||||||
|
* @param elementType the element type within {@code Flux/Mono} that we're
|
||||||
|
* trying to encode.
|
||||||
|
* @param request the current request
|
||||||
|
* @param response the current response
|
||||||
|
* @return a Map with hints, possibly empty
|
||||||
|
*/
|
||||||
|
Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||||
|
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -35,6 +35,8 @@ import org.springframework.core.io.buffer.DataBuffer;
|
|||||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ReactiveHttpOutputMessage;
|
import org.springframework.http.ReactiveHttpOutputMessage;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.MimeTypeUtils;
|
import org.springframework.util.MimeTypeUtils;
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@ import org.springframework.util.MimeTypeUtils;
|
|||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Object> {
|
public class ServerSentEventHttpMessageWriter implements ServerHttpMessageWriter<Object> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server-Sent Events hint key expecting a {@link Boolean} value which when set to true
|
* Server-Sent Events hint key expecting a {@link Boolean} value which when set to true
|
||||||
@@ -161,4 +163,23 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||||||
return Mono.just(buffer);
|
return Mono.just(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> write(Publisher<?> inputStream, ResolvableType streamType, ResolvableType elementType,
|
||||||
|
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response,
|
||||||
|
Map<String, Object> hints) {
|
||||||
|
|
||||||
|
Map<String, Object> allHints = this.dataEncoders.stream()
|
||||||
|
.filter(encoder -> encoder instanceof ServerHttpEncoder)
|
||||||
|
.map(encoder -> (ServerHttpEncoder<?>) encoder)
|
||||||
|
.map(encoder -> encoder.getEncodeHints(streamType, elementType, mediaType, request, response))
|
||||||
|
.reduce(new HashMap<>(), (t, u) -> {
|
||||||
|
t.putAll(u);
|
||||||
|
return t;
|
||||||
|
});
|
||||||
|
|
||||||
|
allHints.putAll(hints);
|
||||||
|
|
||||||
|
return write(inputStream, elementType, mediaType, response, allHints);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,11 @@
|
|||||||
package org.springframework.http.codec.json;
|
package org.springframework.http.codec.json;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectReader;
|
import com.fasterxml.jackson.databind.ObjectReader;
|
||||||
@@ -30,10 +32,12 @@ import reactor.core.publisher.Mono;
|
|||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.codec.CodecException;
|
import org.springframework.core.codec.CodecException;
|
||||||
import org.springframework.core.codec.Decoder;
|
|
||||||
import org.springframework.core.io.buffer.DataBuffer;
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
|
import org.springframework.http.codec.ServerHttpDecoder;
|
||||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.MimeType;
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
@@ -45,7 +49,7 @@ import org.springframework.util.MimeType;
|
|||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see Jackson2JsonEncoder
|
* @see Jackson2JsonEncoder
|
||||||
*/
|
*/
|
||||||
public class Jackson2JsonDecoder extends AbstractJackson2Codec implements Decoder<Object> {
|
public class Jackson2JsonDecoder extends AbstractJackson2Codec implements ServerHttpDecoder<Object> {
|
||||||
|
|
||||||
private final JsonObjectDecoder fluxObjectDecoder = new JsonObjectDecoder(true);
|
private final JsonObjectDecoder fluxObjectDecoder = new JsonObjectDecoder(true);
|
||||||
|
|
||||||
@@ -123,4 +127,27 @@ public class Jackson2JsonDecoder extends AbstractJackson2Codec implements Decode
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ServerHttpDecoder...
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getDecodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||||
|
ServerHttpRequest request, ServerHttpResponse response) {
|
||||||
|
|
||||||
|
Object source = actualType.getSource();
|
||||||
|
MethodParameter parameter = (source instanceof MethodParameter ? (MethodParameter)source : null);
|
||||||
|
if (parameter != null) {
|
||||||
|
JsonView annotation = parameter.getParameterAnnotation(JsonView.class);
|
||||||
|
if (annotation != null) {
|
||||||
|
Class<?>[] classes = annotation.value();
|
||||||
|
if (classes.length != 1) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"@JsonView only supported for read hints with exactly 1 class argument: " + parameter);
|
||||||
|
}
|
||||||
|
return Collections.singletonMap(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ package org.springframework.http.codec.json;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
import com.fasterxml.jackson.core.PrettyPrinter;
|
import com.fasterxml.jackson.core.PrettyPrinter;
|
||||||
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
import com.fasterxml.jackson.core.util.DefaultIndenter;
|
||||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||||
@@ -31,20 +33,25 @@ import com.fasterxml.jackson.databind.SerializationConfig;
|
|||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON;
|
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.core.codec.CodecException;
|
import org.springframework.core.codec.CodecException;
|
||||||
import org.springframework.core.codec.Encoder;
|
|
||||||
import org.springframework.core.io.buffer.DataBuffer;
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.codec.ServerHttpEncoder;
|
||||||
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
|
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
|
||||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.MimeType;
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
|
import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode from an {@code Object} stream to a byte stream of JSON objects,
|
* Encode from an {@code Object} stream to a byte stream of JSON objects,
|
||||||
* using Jackson 2.6+.
|
* using Jackson 2.6+.
|
||||||
@@ -54,7 +61,7 @@ import org.springframework.util.MimeType;
|
|||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see Jackson2JsonDecoder
|
* @see Jackson2JsonDecoder
|
||||||
*/
|
*/
|
||||||
public class Jackson2JsonEncoder extends AbstractJackson2Codec implements Encoder<Object> {
|
public class Jackson2JsonEncoder extends AbstractJackson2Codec implements ServerHttpEncoder<Object> {
|
||||||
|
|
||||||
private final PrettyPrinter ssePrettyPrinter;
|
private final PrettyPrinter ssePrettyPrinter;
|
||||||
|
|
||||||
@@ -144,4 +151,28 @@ public class Jackson2JsonEncoder extends AbstractJackson2Codec implements Encode
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ServerHttpEncoder...
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||||
|
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||||
|
|
||||||
|
Map<String, Object> hints = new HashMap<>();
|
||||||
|
Object source = actualType.getSource();
|
||||||
|
MethodParameter returnValue = (source instanceof MethodParameter ? (MethodParameter)source : null);
|
||||||
|
if (returnValue != null) {
|
||||||
|
JsonView annotation = returnValue.getMethodAnnotation(JsonView.class);
|
||||||
|
if (annotation != null) {
|
||||||
|
Class<?>[] classes = annotation.value();
|
||||||
|
if (classes.length != 1) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"@JsonView only supported for write hints with exactly 1 class argument: " + returnValue);
|
||||||
|
}
|
||||||
|
hints.put(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hints;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import org.springframework.http.codec.DecoderHttpMessageReader;
|
|||||||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||||
import org.springframework.http.codec.HttpMessageReader;
|
import org.springframework.http.codec.HttpMessageReader;
|
||||||
import org.springframework.http.codec.HttpMessageWriter;
|
import org.springframework.http.codec.HttpMessageWriter;
|
||||||
import org.springframework.http.codec.Jackson2ServerHttpMessageReader;
|
|
||||||
import org.springframework.http.codec.Jackson2ServerHttpMessageWriter;
|
import org.springframework.http.codec.Jackson2ServerHttpMessageWriter;
|
||||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||||
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
|
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
|
||||||
@@ -339,8 +338,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
|||||||
readers.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder()));
|
readers.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder()));
|
||||||
}
|
}
|
||||||
if (jackson2Present) {
|
if (jackson2Present) {
|
||||||
readers.add(new Jackson2ServerHttpMessageReader(
|
readers.add(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
|
||||||
new DecoderHttpMessageReader<>(new Jackson2JsonDecoder())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user