Merge branch '5.1.x'

This commit is contained in:
Rossen Stoyanchev 2019-01-18 18:29:39 -05:00
commit b0a3a6f79f
7 changed files with 89 additions and 22 deletions

View File

@ -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");
}
}
}

View File

@ -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));
}
});
}

View File

@ -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

View File

@ -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 =

View File

@ -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;
}
/**

View File

@ -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

View File

@ -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.