Polishing

This commit is contained in:
Juergen Hoeller 2017-04-10 15:36:45 +02:00
parent cf306037b5
commit 15b5dd9f12
12 changed files with 103 additions and 79 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -256,8 +256,8 @@ public abstract class AbstractApplicationEventMulticaster
* for the given event type
*/
protected boolean supportsEvent(Class<?> listenerType, ResolvableType eventType) {
if (GenericApplicationListener.class.isAssignableFrom(listenerType)
|| SmartApplicationListener.class.isAssignableFrom(listenerType)) {
if (GenericApplicationListener.class.isAssignableFrom(listenerType) ||
SmartApplicationListener.class.isAssignableFrom(listenerType)) {
return true;
}
ResolvableType declaredEventType = GenericApplicationListenerAdapter.resolveDeclaredEventType(listenerType);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* 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.
@ -79,6 +79,7 @@ public interface ApplicationEventMulticaster {
* based on the {@code event} instance.
* @param event the event to multicast
* @param eventType the type of event (can be null)
* @since 4.2
*/
void multicastEvent(ApplicationEvent event, ResolvableType eventType);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -144,7 +144,7 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton,
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType);
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -27,8 +27,10 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@ -39,6 +41,7 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@ -546,6 +549,14 @@ public class AnnotationDrivenEventListenerTests {
assertThat(listener.order, contains("first", "second", "third"));
}
@Test @Ignore // SPR-15122
public void listenersReceiveEarlyEvents() {
load(EventOnPostConstruct.class, OrderedTestListener.class);
OrderedTestListener listener = this.context.getBean(OrderedTestListener.class);
assertThat(listener.order, contains("first", "second", "third"));
}
private void load(Class<?>... classes) {
List<Class<?>> allClasses = new ArrayList<>();
@ -936,6 +947,18 @@ public class AnnotationDrivenEventListenerTests {
}
static class EventOnPostConstruct {
@Autowired
ApplicationEventPublisher publisher;
@PostConstruct
public void init() {
this.publisher.publishEvent("earlyEvent");
}
}
private static class CustomScope implements org.springframework.beans.factory.config.Scope {
public boolean active = true;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* 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.
@ -67,14 +67,14 @@ public interface GenericHttpMessageConverter<T> extends HttpMessageConverter<T>
/**
* Indicates whether the given class can be written by this converter.
* This method should perform the same checks than
* <p>This method should perform the same checks than
* {@link HttpMessageConverter#canWrite(Class, MediaType)} with additional ones
* related to the generic type.
* @param type the (potentially generic) type to test for writability, can be
* {@code null} if not specified.
* @param type the (potentially generic) type to test for writability
* (can be {@code null} if not specified)
* @param clazz the source object class to test for writability
* @param mediaType the media type to write, can be {@code null} if not specified.
* Typically the value of an {@code Accept} header.
* @param mediaType the media type to write (can be {@code null} if not specified);
* typically the value of an {@code Accept} header.
* @return {@code true} if writable; {@code false} otherwise
* @since 4.2
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* 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.
@ -35,8 +35,8 @@ public interface HttpMessageConverter<T> {
/**
* Indicates whether the given class can be read by this converter.
* @param clazz the class to test for readability
* @param mediaType the media type to read, can be {@code null} if not specified.
* Typically the value of a {@code Content-Type} header.
* @param mediaType the media type to read (can be {@code null} if not specified);
* typically the value of a {@code Content-Type} header.
* @return {@code true} if readable; {@code false} otherwise
*/
boolean canRead(Class<?> clazz, MediaType mediaType);
@ -44,8 +44,8 @@ public interface HttpMessageConverter<T> {
/**
* Indicates whether the given class can be written by this converter.
* @param clazz the class to test for writability
* @param mediaType the media type to write, can be {@code null} if not specified.
* Typically the value of an {@code Accept} header.
* @param mediaType the media type to write (can be {@code null} if not specified);
* typically the value of an {@code Accept} header.
* @return {@code true} if writable; {@code false} otherwise
*/
boolean canWrite(Class<?> clazz, MediaType mediaType);

View File

@ -0,0 +1,4 @@
/**
* Provides an HttpMessageConverter for the CBOR data format.
*/
package org.springframework.http.converter.cbor;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -50,17 +50,16 @@ import org.springframework.util.ClassUtils;
*
* <p>Other formats can be supported with additional libraries:
* <ul>
* <li>{@code "application/json"} with the official library
* {@code "com.google.protobuf:protobuf-java-util"}
* <li>{@code "application/json"}, {@code "application/xml"} and {@code "text/html"} (write only)
* can be supported with the 3rd party library
* {@code "com.googlecode.protobuf-java-format:protobuf-java-format"}
* <li>{@code "application/json"} with the official library
* {@code "com.google.protobuf:protobuf-java-util"}
* <li>{@code "application/json"}, {@code "application/xml"} and {@code "text/html"} (write only)
* can be supported with the 3rd party library
* {@code "com.googlecode.protobuf-java-format:protobuf-java-format"}
* </ul>
*
* <p>To generate {@code Message} Java classes, you need to install the {@code protoc} binary.
*
* <p>Requires Protobuf 2.6 and Protobuf Java Format 1.4, as of Spring 4.3.
* Supports up to Protobuf 3.0.0.
* <p>Requires Protobuf 2.6 or 3.x and Protobuf Java Format 1.4 or higher, as of Spring 5.0.
*
* @author Alex Antonov
* @author Brian Clozel
@ -83,14 +82,15 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
private static final boolean isProtobufJavaFormatPresent =
ClassUtils.isPresent("com.googlecode.protobuf.format.JsonFormat", ProtobufHttpMessageConverter.class.getClassLoader());
private static final MediaType[] SUPPORTED_MEDIATYPES;
private final ProtobufFormatsSupport protobufFormatsSupport;
private static final ConcurrentHashMap<Class<?>, Method> methodCache = new ConcurrentHashMap<>();
private final ProtobufFormatSupport protobufFormatSupport;
private final ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
private static final MediaType[] SUPPORTED_MEDIATYPES;
static {
if (isProtobufJavaFormatPresent) {
SUPPORTED_MEDIATYPES = new MediaType[] {PROTOBUF, MediaType.TEXT_PLAIN, MediaType.APPLICATION_XML,
@ -104,27 +104,28 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
}
}
/**
* Construct a new instance.
* Construct a new {@code ProtobufHttpMessageConverter}.
*/
public ProtobufHttpMessageConverter() {
this(null);
}
/**
* Construct a new instance with an {@link ExtensionRegistryInitializer}
* that allows the registration of message extensions.
* Construct a new {@code ProtobufHttpMessageConverter} with an
* initializer that allows the registration of message extensions.
*/
public ProtobufHttpMessageConverter(ExtensionRegistryInitializer registryInitializer) {
super(SUPPORTED_MEDIATYPES);
if (isProtobufJavaFormatPresent) {
this.protobufFormatsSupport = new ProtobufJavaFormatSupport();
this.protobufFormatSupport = new ProtobufJavaFormatSupport();
}
else if (isProtobufJavaUtilPresent) {
this.protobufFormatsSupport = new ProtobufJavaUtilSupport();
this.protobufFormatSupport = new ProtobufJavaUtilSupport();
}
else {
this.protobufFormatsSupport = null;
this.protobufFormatSupport = null;
}
if (registryInitializer != null) {
registryInitializer.initializeExtensionRegistry(this.extensionRegistry);
@ -165,7 +166,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
TextFormat.merge(reader, this.extensionRegistry, builder);
}
else if (isProtobufJavaUtilPresent || isProtobufJavaFormatPresent) {
this.protobufFormatsSupport.merge(inputMessage.getBody(), charset, contentType,
this.protobufFormatSupport.merge(inputMessage.getBody(), charset, contentType,
this.extensionRegistry, builder);
}
return builder.build();
@ -211,7 +212,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
outputMessage.getBody().flush();
}
else if (isProtobufJavaUtilPresent || isProtobufJavaFormatPresent) {
this.protobufFormatsSupport.print(message, outputMessage.getBody(), contentType, charset);
this.protobufFormatSupport.print(message, outputMessage.getBody(), contentType, charset);
outputMessage.getBody().flush();
}
}
@ -241,15 +242,17 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
return (Message.Builder) method.invoke(clazz);
}
private interface ProtobufFormatsSupport {
void merge(InputStream input, Charset cs, MediaType contentType, ExtensionRegistry extensionRegistry,
private interface ProtobufFormatSupport {
void merge(InputStream input, Charset charset, MediaType contentType, ExtensionRegistry extensionRegistry,
Message.Builder builder) throws IOException;
void print(Message message, OutputStream output, MediaType contentType, Charset cs) throws IOException;
}
private class ProtobufJavaUtilSupport implements ProtobufFormatsSupport {
private class ProtobufJavaUtilSupport implements ProtobufFormatSupport {
private final com.google.protobuf.util.JsonFormat.Parser parser;
@ -261,16 +264,16 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
}
@Override
public void merge(InputStream input, Charset cs, MediaType contentType,
public void merge(InputStream input, Charset charset, MediaType contentType,
ExtensionRegistry extensionRegistry, Message.Builder builder) throws IOException {
if (contentType.isCompatibleWith(MediaType.APPLICATION_JSON)) {
InputStreamReader reader = new InputStreamReader(input, cs);
InputStreamReader reader = new InputStreamReader(input, charset);
this.parser.merge(reader, builder);
}
else {
throw new UnsupportedOperationException("com.googlecode.protobuf:protobuf-java-util does not support "
+ contentType.toString() + " format");
throw new IOException(
"com.googlecode.protobuf:protobuf-java-util does not support " + contentType + " format");
}
}
@ -280,14 +283,14 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
this.printer.appendTo(message, new OutputStreamWriter(output, cs));
}
else {
throw new UnsupportedOperationException("com.googlecode.protobuf:protobuf-java-util does not support "
+ contentType.toString() + " format");
throw new IOException(
"com.googlecode.protobuf:protobuf-java-util does not support " + contentType + " format");
}
}
}
private class ProtobufJavaFormatSupport implements ProtobufFormatsSupport {
private class ProtobufJavaFormatSupport implements ProtobufFormatSupport {
private final FormatFactory FORMAT_FACTORY;
@ -305,17 +308,17 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
}
@Override
public void merge(InputStream input, Charset cs, MediaType contentType,
public void merge(InputStream input, Charset charset, MediaType contentType,
ExtensionRegistry extensionRegistry, Message.Builder builder) throws IOException {
if (contentType.isCompatibleWith(MediaType.APPLICATION_JSON)) {
JSON_FORMATTER.merge(input, cs, extensionRegistry, builder);
JSON_FORMATTER.merge(input, charset, extensionRegistry, builder);
}
else if (contentType.isCompatibleWith(MediaType.APPLICATION_XML)) {
XML_FORMATTER.merge(input, cs, extensionRegistry, builder);
XML_FORMATTER.merge(input, charset, extensionRegistry, builder);
}
else {
throw new UnsupportedOperationException("com.google.protobuf.util does not support "
+ contentType.toString() + " format");
throw new IOException("com.google.protobuf.util does not support " + contentType + " format");
}
}
@ -331,8 +334,7 @@ public class ProtobufHttpMessageConverter extends AbstractHttpMessageConverter<M
HTML_FORMATTER.print(message, output, cs);
}
else {
throw new UnsupportedOperationException("com.google.protobuf.util does not support "
+ contentType.toString() + " format");
throw new IOException("com.google.protobuf.util does not support " + contentType + " format");
}
}
}

View File

@ -0,0 +1,4 @@
/**
* Provides an HttpMessageConverter for the Smile data format ("binary JSON").
*/
package org.springframework.http.converter.smile;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -137,8 +137,7 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
String prefix = getForwardedPrefix(request);
this.contextPath = (prefix != null ? prefix : request.getContextPath());
this.requestUri = this.contextPath + pathHelper.getPathWithinApplication(request);
this.requestUrl = this.scheme + "://" + this.host +
(port == -1 ? "" : ":" + port) + this.requestUri;
this.requestUrl = this.scheme + "://" + this.host + (port == -1 ? "" : ":" + port) + this.requestUri;
this.headers = initHeaders(request);
}
@ -229,13 +228,13 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
}
}
private static class ForwardedHeaderResponseWrapper extends HttpServletResponseWrapper {
private static final String FOLDER_SEPARATOR = "/";
private final HttpServletRequest request;
public ForwardedHeaderResponseWrapper(HttpServletResponse response, HttpServletRequest request) {
super(response);
this.request = request;
@ -243,7 +242,6 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
@Override
public void sendRedirect(String location) throws IOException {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(location);
// Absolute location
@ -253,20 +251,15 @@ public class ForwardedHeaderFilter extends OncePerRequestFilter {
}
// Network-path reference
if(location.startsWith("//")) {
if (location.startsWith("//")) {
String scheme = this.request.getScheme();
super.sendRedirect(builder.scheme(scheme).toUriString());
return;
}
// Relative to Servlet container root or to current request
String path;
if (location.startsWith(FOLDER_SEPARATOR)) {
path = location;
}
else {
path = StringUtils.applyRelativePath(this.request.getRequestURI(), location);
}
String path = (location.startsWith(FOLDER_SEPARATOR) ? location :
StringUtils.applyRelativePath(this.request.getRequestURI(), location));
String result = UriComponentsBuilder
.fromHttpRequest(new ServletServerHttpRequest(this.request))

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* 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.
@ -31,7 +31,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.core.ParameterizedTypeReference;
@ -162,7 +161,6 @@ public class MappingJackson2HttpMessageConverterTests {
@SuppressWarnings("unchecked")
public void readGenerics() throws IOException {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter() {
@Override
protected JavaType getJavaType(Type type, Class<?> contextClass) {
if (type instanceof Class && List.class.isAssignableFrom((Class<?>)type)) {
@ -555,6 +553,7 @@ public class MappingJackson2HttpMessageConverterTests {
}
}
private static class BeanWithNoDefaultConstructor {
private final String property1;
@ -573,7 +572,6 @@ public class MappingJackson2HttpMessageConverterTests {
public String getProperty2() {
return property2;
}
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.mvc.method.annotation;
import java.util.concurrent.CompletableFuture;
@ -33,10 +34,8 @@ import org.springframework.web.context.request.async.StandardServletAsyncWebRequ
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.method.support.ModelAndViewContainer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.method.ResolvableMethod.on;
import static org.junit.Assert.*;
import static org.springframework.web.method.ResolvableMethod.*;
/**
* Unit tests for {@link DeferredResultMethodReturnValueHandler}.
@ -67,7 +66,6 @@ public class DeferredResultReturnValueHandlerTests {
@Test
public void supportsReturnType() throws Exception {
assertTrue(this.handler.supportsReturnType(
on(TestController.class).resolveReturnType(DeferredResult.class, String.class)));
@ -103,7 +101,7 @@ public class DeferredResultReturnValueHandlerTests {
}
@Test
public void deferredResultWitError() throws Exception {
public void deferredResultWithError() throws Exception {
DeferredResult<String> result = new DeferredResult<>();
testHandle(result, DeferredResult.class, () -> result.setResult("foo"), "foo");
}
@ -122,6 +120,7 @@ public class DeferredResultReturnValueHandlerTests {
testHandle(future, CompletableFuture.class, () -> future.setException(ex), ex);
}
private void testHandle(Object returnValue, Class<?> asyncType,
Runnable setResultTask, Object expectedValue) throws Exception {