Merge branch '5.1.x'
This commit is contained in:
commit
b0a3a6f79f
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -119,21 +119,21 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
|
|||
for (String line : lines) {
|
||||
if (line.startsWith("data:")) {
|
||||
data = (data != null ? data : new StringBuilder());
|
||||
data.append(line.substring(5)).append("\n");
|
||||
data.append(line.substring(5).trim()).append("\n");
|
||||
}
|
||||
if (shouldWrap) {
|
||||
if (line.startsWith("id:")) {
|
||||
sseBuilder.id(line.substring(3));
|
||||
sseBuilder.id(line.substring(3).trim());
|
||||
}
|
||||
else if (line.startsWith("event:")) {
|
||||
sseBuilder.event(line.substring(6));
|
||||
sseBuilder.event(line.substring(6).trim());
|
||||
}
|
||||
else if (line.startsWith("retry:")) {
|
||||
sseBuilder.retry(Duration.ofMillis(Long.valueOf(line.substring(6))));
|
||||
sseBuilder.retry(Duration.ofMillis(Long.valueOf(line.substring(6).trim())));
|
||||
}
|
||||
else if (line.startsWith(":")) {
|
||||
comment = (comment != null ? comment : new StringBuilder());
|
||||
comment.append(line.substring(1)).append("\n");
|
||||
comment.append(line.substring(1).trim()).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -113,7 +113,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple
|
|||
getObjectMapper().readerWithView(jsonView).forType(javaType) :
|
||||
getObjectMapper().readerFor(javaType));
|
||||
|
||||
return tokens.map(tokenBuffer -> {
|
||||
return tokens.flatMap(tokenBuffer -> {
|
||||
try {
|
||||
Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper()));
|
||||
if (!Hints.isLoggingSuppressed(hints)) {
|
||||
|
@ -122,16 +122,16 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple
|
|||
return Hints.getLogPrefix(hints) + "Decoded [" + formatted + "]";
|
||||
});
|
||||
}
|
||||
return value;
|
||||
return Mono.justOrEmpty(value);
|
||||
}
|
||||
catch (InvalidDefinitionException ex) {
|
||||
throw new CodecException("Type definition error: " + ex.getType(), ex);
|
||||
return Mono.error(new CodecException("Type definition error: " + ex.getType(), ex));
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
throw new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex);
|
||||
return Mono.error(new DecodingException("JSON decoding error: " + ex.getOriginalMessage(), ex));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DecodingException("I/O error while parsing input stream", ex);
|
||||
return Mono.error(new DecodingException("I/O error while parsing input stream", ex));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -77,7 +77,8 @@ import org.springframework.web.util.UriTemplateHandler;
|
|||
* modern alternative to the {@code RestTemplate} with efficient support for
|
||||
* both sync and async, as well as streaming scenarios. The {@code RestTemplate}
|
||||
* will be deprecated in a future version and will not have major new features
|
||||
* added going forward.
|
||||
* added going forward. See the WebClient section of the Spring Framework reference
|
||||
* documentation for more details and example code.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Brian Clozel
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -38,6 +38,7 @@ import org.springframework.core.codec.AbstractDecoderTestCase;
|
|||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.codec.DecodingException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.Pojo;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
|
@ -174,6 +175,14 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTestCase<Jackson2Js
|
|||
.verifyError(DecodingException.class));
|
||||
}
|
||||
|
||||
@Test // #22042
|
||||
public void decodeWithNullLiteral() {
|
||||
Flux<Object> result = this.decoder.decode(Flux.concat(stringBuffer("null")),
|
||||
ResolvableType.forType(Pojo.class), MediaType.APPLICATION_JSON, Collections.emptyMap());
|
||||
|
||||
StepVerifier.create(result).expectComplete().verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noDefaultConstructor() {
|
||||
Flux<DataBuffer> input =
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
|
@ -99,14 +100,16 @@ public abstract class AbstractHandlerExceptionResolver implements HandlerExcepti
|
|||
/**
|
||||
* Set the log category for warn logging. The name will be passed to the underlying logger
|
||||
* implementation through Commons Logging, getting interpreted as a log category according
|
||||
* to the logger's configuration.
|
||||
* <p>Default is no warn logging. Specify this setting to activate warn logging into a specific
|
||||
* to the logger's configuration. If {@code null} is passed, warn logging is turned off.
|
||||
* <p>By default there is no warn logging although sub-classes like
|
||||
* {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver}
|
||||
* can change that default. Specify this setting to activate warn logging into a specific
|
||||
* category. Alternatively, override the {@link #logException} method for custom logging.
|
||||
* @see org.apache.commons.logging.LogFactory#getLog(String)
|
||||
* @see java.util.logging.Logger#getLogger(String)
|
||||
*/
|
||||
public void setWarnLogCategory(String loggerName) {
|
||||
this.warnLogger = LogFactory.getLog(loggerName);
|
||||
this.warnLogger = !StringUtils.isEmpty(loggerName) ? LogFactory.getLog(loggerName) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -541,6 +541,58 @@ WebClient client = webClient.mutate()
|
|||
|
||||
|
||||
|
||||
[[webflux-client-synchronous]]
|
||||
== Synchronous Use
|
||||
|
||||
`WebClient` can be used in synchronous style by blocking at the end for the result:
|
||||
|
||||
[source,java,intent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
Person person = client.get().uri("/person/{id}", i).retrieve()
|
||||
.bodyToMono(Person.class)
|
||||
.block();
|
||||
|
||||
List<Person> persons = client.get().uri("/persons").retrieve()
|
||||
.bodyToFlux(Person.class)
|
||||
.collectList()
|
||||
.block();
|
||||
----
|
||||
|
||||
However if multiple calls need to be made, it's more efficient to avoid blocking on each
|
||||
response individually, and instead wait for the combined result:
|
||||
|
||||
[source,java,intent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
Mono<Person> personMono = client.get().uri("/person/{id}", personId)
|
||||
.retrieve().bodyToMono(Person.class);
|
||||
|
||||
Mono<List<Hobby>> hobbiesMono = client.get().uri("/person/{id}/hobbies", personId)
|
||||
.retrieve().bodyToFlux(Hobby.class).collectList();
|
||||
|
||||
Map<String, Object> data = Mono.zip(personMono, hobbiesMono, (person, hobbies) -> {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
map.put("person", personName);
|
||||
map.put("hobbies", hobbies);
|
||||
return map;
|
||||
})
|
||||
.block();
|
||||
----
|
||||
|
||||
The above is merely one example. There are lots of other patterns and operators for putting
|
||||
together a reactive pipeline that makes many remote calls, potentially some nested,
|
||||
inter-dependent, without ever blocking until the end.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
You should never have to block in a Spring MVC controller. Simply return the resulting
|
||||
`Flux` or `Mono` from the controller method.
|
||||
====
|
||||
|
||||
|
||||
|
||||
|
||||
[[webflux-client-testing]]
|
||||
== Testing
|
||||
|
||||
|
|
|
@ -14,9 +14,11 @@ Spring REST client and exposes a simple, template-method API over underlying HTT
|
|||
libraries.
|
||||
|
||||
NOTE: As of 5.0, the non-blocking, reactive `WebClient` offers a modern alternative to the
|
||||
`RestTemplate`, with efficient support for both synchronous and asynchronous, as well as streaming
|
||||
scenarios. The `RestTemplate` will be deprecated in a future version and will not have
|
||||
major new features added going forward.
|
||||
`RestTemplate`, with efficient support for both
|
||||
<<web-reactive.adoc#webflux-client-synchronous,synchronous and asynchronous>>, as well as
|
||||
streaming scenarios. The `RestTemplate` will be deprecated in a future version and will
|
||||
not have major new features added going forward.
|
||||
|
||||
|
||||
See <<integration.adoc#rest-client-access,REST Endpoints>> for details.
|
||||
|
||||
|
|
Loading…
Reference in New Issue