43 changed files with 547 additions and 650 deletions
@ -1,107 +0,0 @@
@@ -1,107 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2016 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.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import reactor.core.publisher.Flux; |
||||
import reactor.core.publisher.Mono; |
||||
|
||||
import org.springframework.core.MethodParameter; |
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.ReactiveHttpInputMessage; |
||||
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||
import org.springframework.http.server.reactive.ServerHttpResponse; |
||||
|
||||
/** |
||||
* {@link HttpMessageReader} wrapper that implements {@link ServerHttpMessageReader} in order |
||||
* to allow providing hints to the nested {@code reader} or setting the response status for |
||||
* example, by implementing {@link #resolveReadHints(ResolvableType, ResolvableType, ServerHttpRequest)}. |
||||
* |
||||
* @author Sebastien Deleuze |
||||
* @since 5.0 |
||||
*/ |
||||
public abstract class AbstractServerHttpMessageReader<T> implements ServerHttpMessageReader<T> { |
||||
|
||||
private HttpMessageReader<T> reader; |
||||
|
||||
|
||||
public AbstractServerHttpMessageReader(HttpMessageReader<T> reader) { |
||||
this.reader = reader; |
||||
} |
||||
|
||||
@Override |
||||
public boolean canRead(ResolvableType elementType, MediaType mediaType) { |
||||
return this.reader.canRead(elementType, mediaType); |
||||
} |
||||
|
||||
@Override |
||||
public Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) { |
||||
return this.reader.read(elementType, inputMessage, hints); |
||||
} |
||||
|
||||
@Override |
||||
public Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) { |
||||
return this.reader.readMono(elementType, inputMessage, hints); |
||||
} |
||||
|
||||
@Override |
||||
public List<MediaType> getReadableMediaTypes() { |
||||
return this.reader.getReadableMediaTypes(); |
||||
} |
||||
|
||||
@Override |
||||
public Flux<T> read(ResolvableType streamType, ResolvableType elementType, |
||||
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { |
||||
|
||||
Map<String, Object> mergedHints = new HashMap<>(hints); |
||||
mergedHints.putAll(resolveReadHints(streamType, elementType, request)); |
||||
|
||||
return (this.reader instanceof ServerHttpMessageReader ? |
||||
((ServerHttpMessageReader<T>)this.reader).read(streamType, elementType, request, response, mergedHints) : |
||||
this.read(elementType, request, mergedHints)); |
||||
} |
||||
|
||||
@Override |
||||
public Mono<T> readMono(ResolvableType streamType, ResolvableType elementType, |
||||
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { |
||||
|
||||
Map<String, Object> mergedHints = new HashMap<>(hints); |
||||
mergedHints.putAll(resolveReadHints(streamType, elementType, request)); |
||||
|
||||
return (this.reader instanceof ServerHttpMessageReader ? |
||||
((ServerHttpMessageReader<T>)this.reader).readMono(streamType, elementType, request, response, mergedHints) : |
||||
this.readMono(elementType, request, mergedHints)); |
||||
} |
||||
|
||||
/** |
||||
* Invoked before reading the request to resolve hints by |
||||
* {@link #read(ResolvableType, ResolvableType, ServerHttpRequest, ServerHttpResponse, Map)}. |
||||
* |
||||
* @param streamType the original type used for the method return value. For annotation |
||||
* based controllers, the {@link MethodParameter} is available via {@link ResolvableType#getSource()}. |
||||
* @param elementType the stream element type to process |
||||
* @param request the current HTTP request |
||||
* @return Additional information about how to write the body |
||||
*/ |
||||
protected abstract Map<String, Object> resolveReadHints(ResolvableType streamType, |
||||
ResolvableType elementType, ServerHttpRequest request); |
||||
|
||||
} |
||||
@ -1,93 +0,0 @@
@@ -1,93 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2016 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.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.reactivestreams.Publisher; |
||||
import reactor.core.publisher.Mono; |
||||
|
||||
import org.springframework.core.MethodParameter; |
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.ReactiveHttpOutputMessage; |
||||
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||
import org.springframework.http.server.reactive.ServerHttpResponse; |
||||
|
||||
/** |
||||
* {@link HttpMessageWriter} wrapper that implements {@link ServerHttpMessageWriter} in order |
||||
* to allow providing hints to the nested {@code writer} or setting the response status for |
||||
* example, by implementing {@link #resolveWriteHints(ResolvableType, ResolvableType, MediaType, ServerHttpRequest)}. |
||||
* |
||||
* @author Sebastien Deleuze |
||||
* @since 5.0 |
||||
*/ |
||||
public abstract class AbstractServerHttpMessageWriter<T> implements ServerHttpMessageWriter<T> { |
||||
|
||||
private HttpMessageWriter<T> writer; |
||||
|
||||
|
||||
public AbstractServerHttpMessageWriter(HttpMessageWriter<T> writer) { |
||||
this.writer = writer; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean canWrite(ResolvableType elementType, MediaType mediaType) { |
||||
return this.writer.canWrite(elementType, mediaType); |
||||
} |
||||
|
||||
@Override |
||||
public List<MediaType> getWritableMediaTypes() { |
||||
return this.writer.getWritableMediaTypes(); |
||||
} |
||||
|
||||
@Override |
||||
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType, |
||||
MediaType mediaType, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) { |
||||
return this.writer.write(inputStream, elementType, mediaType, outputMessage, hints); |
||||
} |
||||
|
||||
@Override |
||||
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType streamType, ResolvableType elementType, |
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { |
||||
|
||||
Map<String, Object> mergedHints = new HashMap<>(hints); |
||||
mergedHints.putAll(resolveWriteHints(streamType, elementType, mediaType, request)); |
||||
return (this.writer instanceof ServerHttpMessageWriter ? |
||||
((ServerHttpMessageWriter<T>)this.writer).write(inputStream, streamType, |
||||
elementType, mediaType, request, response, mergedHints) : |
||||
this.writer.write(inputStream, elementType, mediaType, response, mergedHints)); |
||||
} |
||||
|
||||
/** |
||||
* Invoked before writing the response to resolve hints by |
||||
* {@link #write(Publisher, ResolvableType, ResolvableType, MediaType, ServerHttpRequest, ServerHttpResponse, Map)}. |
||||
* @param streamType the original type used for the method return value. For annotation |
||||
* based controllers, the {@link MethodParameter} is available via {@link ResolvableType#getSource()}. |
||||
* @param elementType the stream element type to process |
||||
* @param mediaType the content type to use when writing. May be {@code null} to |
||||
* indicate that the default content type of the converter must be used. |
||||
* @param request the current HTTP request |
||||
* @return additional information about how to write the body |
||||
*/ |
||||
protected abstract Map<String, Object> resolveWriteHints(ResolvableType streamType, ResolvableType elementType, |
||||
MediaType mediaType, ServerHttpRequest request); |
||||
|
||||
} |
||||
@ -1,65 +0,0 @@
@@ -1,65 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2016 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.http.codec.json.AbstractJackson2Codec; |
||||
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||
|
||||
/** |
||||
* {@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 |
||||
* @since 5.0 |
||||
* @see com.fasterxml.jackson.annotation.JsonView |
||||
*/ |
||||
public class Jackson2ServerHttpMessageReader extends AbstractServerHttpMessageReader<Object> { |
||||
|
||||
public Jackson2ServerHttpMessageReader(HttpMessageReader<Object> reader) { |
||||
super(reader); |
||||
} |
||||
|
||||
@Override |
||||
protected Map<String, Object> resolveReadHints(ResolvableType streamType, |
||||
ResolvableType elementType, ServerHttpRequest request) { |
||||
|
||||
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(); |
||||
} |
||||
|
||||
} |
||||
@ -1,103 +0,0 @@
@@ -1,103 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2016 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.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView; |
||||
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 org.springframework.core.MethodParameter; |
||||
import org.springframework.core.ResolvableType; |
||||
import org.springframework.core.codec.AbstractEncoder; |
||||
import org.springframework.core.codec.Encoder; |
||||
import org.springframework.http.MediaType; |
||||
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.ServerHttpResponse; |
||||
|
||||
/** |
||||
* Jackson {@link ServerHttpMessageWriter} that resolves {@code @JsonView} annotated handler |
||||
* method and deals with {@link AbstractEncoder#FLUSHING_STRATEGY_HINT}. |
||||
* |
||||
* @author Sebastien Deleuze |
||||
* @since 5.0 |
||||
* @see com.fasterxml.jackson.annotation.JsonView |
||||
*/ |
||||
public class Jackson2ServerHttpMessageWriter extends AbstractServerHttpMessageWriter<Object> { |
||||
|
||||
|
||||
public Jackson2ServerHttpMessageWriter(Encoder<Object> encoder) { |
||||
super(new EncoderHttpMessageWriter<>(encoder)); |
||||
} |
||||
|
||||
public Jackson2ServerHttpMessageWriter(HttpMessageWriter<Object> writer) { |
||||
super(writer); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected Map<String, Object> resolveWriteHints(ResolvableType streamType, |
||||
ResolvableType elementType, MediaType mediaType, ServerHttpRequest request) { |
||||
|
||||
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; |
||||
} |
||||
|
||||
@Override |
||||
public Mono<Void> write(Publisher<?> inputStream, ResolvableType elementType, MediaType mediaType, |
||||
ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) { |
||||
|
||||
if ((mediaType != null) && mediaType.isCompatibleWith(MediaType.APPLICATION_STREAM_JSON)) { |
||||
Map<String, Object> hintsWithFlush = new HashMap<>(hints); |
||||
hintsWithFlush.put(FLUSHING_STRATEGY_HINT, AFTER_EACH_ELEMENT); |
||||
return super.write(inputStream, elementType, mediaType, outputMessage, hintsWithFlush); |
||||
} |
||||
return super.write(inputStream, elementType, mediaType, outputMessage, hints); |
||||
} |
||||
|
||||
@Override |
||||
public Mono<Void> write(Publisher<?> inputStream, ResolvableType streamType, ResolvableType elementType, |
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) { |
||||
|
||||
if ((mediaType != null) && mediaType.isCompatibleWith(MediaType.APPLICATION_STREAM_JSON)) { |
||||
Map<String, Object> hintsWithFlush = new HashMap<>(hints); |
||||
hintsWithFlush.put(FLUSHING_STRATEGY_HINT, AFTER_EACH_ELEMENT); |
||||
return super.write(inputStream, streamType, elementType, mediaType, request, response, hintsWithFlush); |
||||
} |
||||
return super.write(inputStream, streamType, elementType, mediaType, request, response, hints); |
||||
} |
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* 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,52 @@
@@ -0,0 +1,52 @@
|
||||
/* |
||||
* 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); |
||||
|
||||
} |
||||
Loading…
Reference in new issue