Use new Java features (switch expressions, text blocks, new JDK methods)

Closes gh-29747
This commit is contained in:
Krzysztof Krason 2022-12-28 08:59:08 +01:00 committed by Sam Brannen
parent 48abd493fe
commit afb8a0d1b1
53 changed files with 498 additions and 552 deletions

View File

@ -244,31 +244,18 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
int algorithmicStep = STEP_JOIN_POINT_BINDING; int algorithmicStep = STEP_JOIN_POINT_BINDING;
while ((this.numberOfRemainingUnboundArguments > 0) && algorithmicStep < STEP_FINISHED) { while ((this.numberOfRemainingUnboundArguments > 0) && algorithmicStep < STEP_FINISHED) {
switch (algorithmicStep++) { switch (algorithmicStep++) {
case STEP_JOIN_POINT_BINDING: case STEP_JOIN_POINT_BINDING -> {
if (!maybeBindThisJoinPoint()) { if (!maybeBindThisJoinPoint()) {
maybeBindThisJoinPointStaticPart(); maybeBindThisJoinPointStaticPart();
} }
break; }
case STEP_THROWING_BINDING: case STEP_THROWING_BINDING -> maybeBindThrowingVariable();
maybeBindThrowingVariable(); case STEP_ANNOTATION_BINDING -> maybeBindAnnotationsFromPointcutExpression();
break; case STEP_RETURNING_BINDING -> maybeBindReturningVariable();
case STEP_ANNOTATION_BINDING: case STEP_PRIMITIVE_ARGS_BINDING -> maybeBindPrimitiveArgsFromPointcutExpression();
maybeBindAnnotationsFromPointcutExpression(); case STEP_THIS_TARGET_ARGS_BINDING -> maybeBindThisOrTargetOrArgsFromPointcutExpression();
break; case STEP_REFERENCE_PCUT_BINDING -> maybeBindReferencePointcutParameter();
case STEP_RETURNING_BINDING: default -> throw new IllegalStateException("Unknown algorithmic step: " + (algorithmicStep - 1));
maybeBindReturningVariable();
break;
case STEP_PRIMITIVE_ARGS_BINDING:
maybeBindPrimitiveArgsFromPointcutExpression();
break;
case STEP_THIS_TARGET_ARGS_BINDING:
maybeBindThisOrTargetOrArgsFromPointcutExpression();
break;
case STEP_REFERENCE_PCUT_BINDING:
maybeBindReferencePointcutParameter();
break;
default:
throw new IllegalStateException("Unknown algorithmic step: " + (algorithmicStep - 1));
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -128,8 +128,7 @@ abstract class AutowireUtils {
* @return the resolved value * @return the resolved value
*/ */
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) { public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) { if (autowiringValue instanceof ObjectFactory<?> factory && !requiredType.isInstance(autowiringValue)) {
ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
if (autowiringValue instanceof Serializable && requiredType.isInterface()) { if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(), autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory)); new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
@ -275,22 +274,19 @@ abstract class AutowireUtils {
@Override @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) { return switch (method.getName()) {
case "equals": case "equals" -> (proxy == args[0]); // Only consider equal when proxies are identical.
// Only consider equal when proxies are identical. case "hashCode" -> System.identityHashCode(proxy); // Use hashCode of proxy.
return (proxy == args[0]); case "toString" -> this.objectFactory.toString();
case "hashCode": default -> {
// Use hashCode of proxy. try {
return System.identityHashCode(proxy); yield method.invoke(this.objectFactory.getObject(), args);
case "toString": }
return this.objectFactory.toString(); catch (InvocationTargetException ex) {
} throw ex.getTargetException();
try { }
return method.invoke(this.objectFactory.getObject(), args); }
} };
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
} }
} }

View File

@ -365,8 +365,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
for (Map.Entry<String, Object> entry : this.beans.entrySet()) { for (Map.Entry<String, Object> entry : this.beans.entrySet()) {
String beanName = entry.getKey(); String beanName = entry.getKey();
Object beanInstance = entry.getValue(); Object beanInstance = entry.getValue();
if (beanInstance instanceof FactoryBean && !isFactoryType) { if (beanInstance instanceof FactoryBean<?> factoryBean && !isFactoryType) {
FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
Class<?> objectType = factoryBean.getObjectType(); Class<?> objectType = factoryBean.getObjectType();
if ((includeNonSingletons || factoryBean.isSingleton()) && if ((includeNonSingletons || factoryBean.isSingleton()) &&
objectType != null && (type == null || type.isAssignableFrom(objectType))) { objectType != null && (type == null || type.isAssignableFrom(objectType))) {
@ -409,9 +408,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
String beanName = entry.getKey(); String beanName = entry.getKey();
Object beanInstance = entry.getValue(); Object beanInstance = entry.getValue();
// Is bean a FactoryBean? // Is bean a FactoryBean?
if (beanInstance instanceof FactoryBean && !isFactoryType) { if (beanInstance instanceof FactoryBean<?> factory && !isFactoryType) {
// Match object created by FactoryBean. // Match object created by FactoryBean.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
Class<?> objectType = factory.getObjectType(); Class<?> objectType = factory.getObjectType();
if ((includeNonSingletons || factory.isSingleton()) && if ((includeNonSingletons || factory.isSingleton()) &&
objectType != null && (type == null || type.isAssignableFrom(objectType))) { objectType != null && (type == null || type.isAssignableFrom(objectType))) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -389,16 +389,17 @@ public class FreeMarkerConfigurationFactory {
*/ */
@Nullable @Nullable
protected TemplateLoader getAggregateTemplateLoader(List<TemplateLoader> templateLoaders) { protected TemplateLoader getAggregateTemplateLoader(List<TemplateLoader> templateLoaders) {
switch (templateLoaders.size()) { return switch (templateLoaders.size()) {
case 0: case 0 -> {
logger.debug("No FreeMarker TemplateLoaders specified"); logger.debug("No FreeMarker TemplateLoaders specified");
return null; yield null;
case 1: }
return templateLoaders.get(0); case 1 -> templateLoaders.get(0);
default: default -> {
TemplateLoader[] loaders = templateLoaders.toArray(new TemplateLoader[0]); TemplateLoader[] loaders = templateLoaders.toArray(new TemplateLoader[0]);
return new MultiTemplateLoader(loaders); yield new MultiTemplateLoader(loaders);
} }
};
} }
/** /**

View File

@ -587,12 +587,11 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
*/ */
protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey) throws MBeanExportException { protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey) throws MBeanExportException {
try { try {
if (mapValue instanceof String) { if (mapValue instanceof String beanName) {
// Bean name pointing to a potentially lazy-init bean in the factory. // Bean name pointing to a potentially lazy-init bean in the factory.
if (this.beanFactory == null) { if (this.beanFactory == null) {
throw new MBeanExportException("Cannot resolve bean names if not running in a BeanFactory"); throw new MBeanExportException("Cannot resolve bean names if not running in a BeanFactory");
} }
String beanName = (String) mapValue;
if (isBeanDefinitionLazyInit(this.beanFactory, beanName)) { if (isBeanDefinitionLazyInit(this.beanFactory, beanName)) {
ObjectName objectName = registerLazyInit(beanName, beanKey); ObjectName objectName = registerLazyInit(beanName, beanKey);
replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName); replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -90,8 +90,7 @@ public abstract class BshScriptUtils {
throws EvalError { throws EvalError {
Object result = evaluateBshScript(scriptSource, scriptInterfaces, classLoader); Object result = evaluateBshScript(scriptSource, scriptInterfaces, classLoader);
if (result instanceof Class) { if (result instanceof Class<?> clazz) {
Class<?> clazz = (Class<?>) result;
try { try {
return ReflectionUtils.accessibleConstructor(clazz).newInstance(); return ReflectionUtils.accessibleConstructor(clazz).newInstance();
} }

View File

@ -160,8 +160,7 @@ public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAwar
} }
} }
if (script instanceof Class) { if (script instanceof Class<?> scriptClass) {
Class<?> scriptClass = (Class<?>) script;
try { try {
return ReflectionUtils.accessibleConstructor(scriptClass).newInstance(); return ReflectionUtils.accessibleConstructor(scriptClass).newInstance();
} }

View File

@ -191,8 +191,7 @@ public class ResourceBundleThemeSource implements HierarchicalThemeSource, BeanC
* @param theme the Theme to (re-)initialize * @param theme the Theme to (re-)initialize
*/ */
protected void initParent(Theme theme) { protected void initParent(Theme theme) {
if (theme.getMessageSource() instanceof HierarchicalMessageSource) { if (theme.getMessageSource() instanceof HierarchicalMessageSource messageSource) {
HierarchicalMessageSource messageSource = (HierarchicalMessageSource) theme.getMessageSource();
if (getParentThemeSource() != null && messageSource.getParentMessageSource() == null) { if (getParentThemeSource() != null && messageSource.getParentMessageSource() == null) {
Theme parentTheme = getParentThemeSource().getTheme(theme.getName()); Theme parentTheme = getParentThemeSource().getTheme(theme.getName());
if (parentTheme != null) { if (parentTheme != null) {

View File

@ -852,8 +852,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
if (pv.getValue() instanceof String) { if (pv.getValue() instanceof String) {
empty = !StringUtils.hasText((String) pv.getValue()); empty = !StringUtils.hasText((String) pv.getValue());
} }
else if (pv.getValue() instanceof String[]) { else if (pv.getValue() instanceof String[] values) {
String[] values = (String[]) pv.getValue();
empty = (values.length == 0 || !StringUtils.hasText(values[0])); empty = (values.length == 0 || !StringUtils.hasText(values[0]));
} }
} }

View File

@ -49,33 +49,35 @@ class ScriptFactoryPostProcessorTests {
private static final String PROCESSOR_BEAN_NAME = "processor"; private static final String PROCESSOR_BEAN_NAME = "processor";
private static final String CHANGED_SCRIPT = "package org.springframework.scripting.groovy\n" + // quote the returned message (this is the change)...
"import org.springframework.scripting.Messenger\n" + private static final String CHANGED_SCRIPT = """
"class GroovyMessenger implements Messenger {\n" + package org.springframework.scripting.groovy
" private String message = \"Bingo\"\n" + import org.springframework.scripting.Messenger
" public String getMessage() {\n" + class GroovyMessenger implements Messenger {
// quote the returned message (this is the change)... private String message = "Bingo"
" return \"'\" + this.message + \"'\"\n" + public String getMessage() {
" }\n" + return "'" + this.message + "'"
" public void setMessage(String message) {\n" + }
" this.message = message\n" + public void setMessage(String message) {
" }\n" + this.message = message
"}"; }
}""";
private static final String EXPECTED_CHANGED_MESSAGE_TEXT = "'" + MESSAGE_TEXT + "'"; private static final String EXPECTED_CHANGED_MESSAGE_TEXT = "'" + MESSAGE_TEXT + "'";
private static final int DEFAULT_SECONDS_TO_PAUSE = 1; private static final int DEFAULT_SECONDS_TO_PAUSE = 1;
private static final String DELEGATING_SCRIPT = "inline:package org.springframework.scripting;\n" + private static final String DELEGATING_SCRIPT = """
"class DelegatingMessenger implements Messenger {\n" + inline:package org.springframework.scripting;
" private Messenger wrappedMessenger;\n" + class DelegatingMessenger implements Messenger {
" public String getMessage() {\n" + private Messenger wrappedMessenger;
" return this.wrappedMessenger.getMessage()\n" + public String getMessage() {
" }\n" + return this.wrappedMessenger.getMessage()
" public void setMessenger(Messenger wrappedMessenger) {\n" + }
" this.wrappedMessenger = wrappedMessenger\n" + public void setMessenger(Messenger wrappedMessenger) {
" }\n" + this.wrappedMessenger = wrappedMessenger
"}"; }
}""";
@Test @Test
@ -245,16 +247,17 @@ class ScriptFactoryPostProcessorTests {
private static BeanDefinition createScriptedGroovyBean() { private static BeanDefinition createScriptedGroovyBean() {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class); BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(GroovyScriptFactory.class);
builder.addConstructorArgValue("inline:package org.springframework.scripting;\n" + builder.addConstructorArgValue("""
"class GroovyMessenger implements Messenger {\n" + inline:package org.springframework.scripting;
" private String message = \"Bingo\"\n" + class GroovyMessenger implements Messenger {
" public String getMessage() {\n" + private String message = "Bingo"
" return this.message\n" + public String getMessage() {
" }\n" + return this.message
" public void setMessage(String message) {\n" + }
" this.message = message\n" + public void setMessage(String message) {
" }\n" + this.message = message
"}"); }
}""");
builder.addPropertyValue("message", MESSAGE_TEXT); builder.addPropertyValue("message", MESSAGE_TEXT);
return builder.getBeanDefinition(); return builder.getBeanDefinition();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -78,11 +78,14 @@ public class StringDecoderBenchmark {
@Setup(Level.Trial) @Setup(Level.Trial)
public void setup() { public void setup() {
String eventTemplate = "id:$1\n" + String eventTemplate = """
"event:some-event\n" + id:$1
":some-comment-$1-aa\n" + event:some-event
":some-comment-$1-bb\n" + :some-comment-$1-aa
"data:abcdefg-$1-hijklmnop-$1-qrstuvw-$1-xyz-$1\n\n"; :some-comment-$1-bb
data:abcdefg-$1-hijklmnop-$1-qrstuvw-$1-xyz-$1
""";
int eventLength = String.format(eventTemplate, String.format("%05d", 1)).length(); int eventLength = String.format(eventTemplate, String.format("%05d", 1)).length();
int eventCount = this.totalSize / eventLength; int eventCount = this.totalSize / eventLength;

View File

@ -152,42 +152,27 @@ class BasicJsonWriter {
private static String escape(CharSequence input) { private static String escape(CharSequence input) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
input.chars().forEach(c -> { input.chars().forEach(c -> builder.append(
switch (c) { switch (c) {
case '"': case '"' -> "\\\"";
builder.append("\\\""); case '\\' -> "\\\\";
break; case '/' -> "\\/";
case '\\': case '\b' -> "\\b";
builder.append("\\\\"); case '\f' -> "\\f";
break; case '\n' -> "\\n";
case '/': case '\r' -> "\\r";
builder.append("\\/"); case '\t' -> "\\t";
break; default -> {
case '\b': if (c <= 0x1F) {
builder.append("\\b"); yield String.format("\\u%04x", c);
break; }
case '\f': else {
builder.append("\\f"); yield (char) c;
break; }
case '\n': }
builder.append("\\n"); }
break; )
case '\r': );
builder.append("\\r");
break;
case '\t':
builder.append("\\t");
break;
default:
if (c <= 0x1F) {
builder.append(String.format("\\u%04x", c));
}
else {
builder.append((char) c);
}
break;
}
});
return builder.toString(); return builder.toString();
} }

View File

@ -314,18 +314,14 @@ public abstract class MimeTypeUtils {
int i = 0; int i = 0;
while (i < mimeTypes.length()) { while (i < mimeTypes.length()) {
switch (mimeTypes.charAt(i)) { switch (mimeTypes.charAt(i)) {
case '"': case '"' -> inQuotes = !inQuotes;
inQuotes = !inQuotes; case ',' -> {
break;
case ',':
if (!inQuotes) { if (!inQuotes) {
tokens.add(mimeTypes.substring(startIndex, i)); tokens.add(mimeTypes.substring(startIndex, i));
startIndex = i + 1; startIndex = i + 1;
} }
break; }
case '\\': case '\\' -> i++;
i++;
break;
} }
i++; i++;
} }

View File

@ -96,18 +96,18 @@ public abstract class FutureAdapter<T, S> implements Future<T> {
@Nullable @Nullable
final T adaptInternal(S adapteeResult) throws ExecutionException { final T adaptInternal(S adapteeResult) throws ExecutionException {
synchronized (this.mutex) { synchronized (this.mutex) {
switch (this.state) { return switch (this.state) {
case SUCCESS: case SUCCESS -> (T) this.result;
return (T) this.result; case FAILURE -> {
case FAILURE:
Assert.state(this.result instanceof ExecutionException, "Failure without exception"); Assert.state(this.result instanceof ExecutionException, "Failure without exception");
throw (ExecutionException) this.result; throw (ExecutionException) this.result;
case NEW: }
case NEW -> {
try { try {
T adapted = adapt(adapteeResult); T adapted = adapt(adapteeResult);
this.result = adapted; this.result = adapted;
this.state = State.SUCCESS; this.state = State.SUCCESS;
return adapted; yield adapted;
} }
catch (ExecutionException ex) { catch (ExecutionException ex) {
this.result = ex; this.result = ex;
@ -120,9 +120,8 @@ public abstract class FutureAdapter<T, S> implements Future<T> {
this.state = State.FAILURE; this.state = State.FAILURE;
throw execEx; throw execEx;
} }
default: }
throw new IllegalStateException(); };
}
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -65,21 +65,19 @@ abstract class AbstractStaxXMLReader extends AbstractXMLReader {
@Override @Override
public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException {
switch (name) { return switch (name) {
case NAMESPACES_FEATURE_NAME: case NAMESPACES_FEATURE_NAME -> this.namespacesFeature;
return this.namespacesFeature; case NAMESPACE_PREFIXES_FEATURE_NAME -> this.namespacePrefixesFeature;
case NAMESPACE_PREFIXES_FEATURE_NAME: case IS_STANDALONE_FEATURE_NAME -> {
return this.namespacePrefixesFeature;
case IS_STANDALONE_FEATURE_NAME:
if (this.isStandalone != null) { if (this.isStandalone != null) {
return this.isStandalone; yield this.isStandalone;
} }
else { else {
throw new SAXNotSupportedException("startDocument() callback not completed yet"); throw new SAXNotSupportedException("startDocument() callback not completed yet");
} }
default: }
return super.getFeature(name); default -> super.getFeature(name);
} };
} }
@Override @Override

View File

@ -274,7 +274,7 @@ public class MethodReference extends SpelNodeImpl {
public boolean isCompilable() { public boolean isCompilable() {
CachedMethodExecutor executorToCheck = this.cachedExecutor; CachedMethodExecutor executorToCheck = this.cachedExecutor;
if (executorToCheck == null || executorToCheck.hasProxyTarget() || if (executorToCheck == null || executorToCheck.hasProxyTarget() ||
!(executorToCheck.get() instanceof ReflectiveMethodExecutor)) { !(executorToCheck.get() instanceof ReflectiveMethodExecutor executor)) {
return false; return false;
} }
@ -284,26 +284,20 @@ public class MethodReference extends SpelNodeImpl {
} }
} }
ReflectiveMethodExecutor executor = (ReflectiveMethodExecutor) executorToCheck.get();
if (executor.didArgumentConversionOccur()) { if (executor.didArgumentConversionOccur()) {
return false; return false;
} }
Class<?> clazz = executor.getMethod().getDeclaringClass(); Class<?> clazz = executor.getMethod().getDeclaringClass();
if (!Modifier.isPublic(clazz.getModifiers()) && executor.getPublicDeclaringClass() == null) { return Modifier.isPublic(clazz.getModifiers()) || executor.getPublicDeclaringClass() != null;
return false;
}
return true;
} }
@Override @Override
public void generateCode(MethodVisitor mv, CodeFlow cf) { public void generateCode(MethodVisitor mv, CodeFlow cf) {
CachedMethodExecutor executorToCheck = this.cachedExecutor; CachedMethodExecutor executorToCheck = this.cachedExecutor;
if (executorToCheck == null || !(executorToCheck.get() instanceof ReflectiveMethodExecutor)) { if (executorToCheck == null || !(executorToCheck.get() instanceof ReflectiveMethodExecutor methodExecutor)) {
throw new IllegalStateException("No applicable cached executor found: " + executorToCheck); throw new IllegalStateException("No applicable cached executor found: " + executorToCheck);
} }
ReflectiveMethodExecutor methodExecutor = (ReflectiveMethodExecutor) executorToCheck.get();
Method method = methodExecutor.getMethod(); Method method = methodExecutor.getMethod();
boolean isStaticMethod = Modifier.isStatic(method.getModifiers()); boolean isStaticMethod = Modifier.isStatic(method.getModifiers());
String descriptor = cf.lastDescriptor(); String descriptor = cf.lastDescriptor();

View File

@ -365,45 +365,54 @@ public class CachingConnectionFactory extends SingleConnectionFactory {
} }
else if (isCacheConsumers()) { else if (isCacheConsumers()) {
// let raw JMS invocation throw an exception if Destination (i.e. args[0]) is null // let raw JMS invocation throw an exception if Destination (i.e. args[0]) is null
if ((methodName.equals("createConsumer") || methodName.equals("createReceiver") || switch (methodName) {
methodName.equals("createSubscriber"))) { case "createConsumer", "createReceiver", "createSubscriber" -> {
Destination dest = (Destination) args[0]; Destination dest = (Destination) args[0];
if (dest != null && !(dest instanceof TemporaryQueue || dest instanceof TemporaryTopic)) { if (dest != null && !(dest instanceof TemporaryQueue || dest instanceof TemporaryTopic)) {
return getCachedConsumer(dest, return getCachedConsumer(
(args.length > 1 ? (String) args[1] : null), dest,
(args.length > 2 && (Boolean) args[2]), (args.length > 1 ? (String) args[1] : null),
null, (args.length > 2 && (Boolean) args[2]),
false); null,
false
);
}
} }
} case "createDurableConsumer", "createDurableSubscriber" -> {
else if (methodName.equals("createDurableConsumer") || methodName.equals("createDurableSubscriber")) { Destination dest = (Destination) args[0];
Destination dest = (Destination) args[0]; if (dest != null) {
if (dest != null) { return getCachedConsumer(
return getCachedConsumer(dest, dest,
(args.length > 2 ? (String) args[2] : null), (args.length > 2 ? (String) args[2] : null),
(args.length > 3 && (Boolean) args[3]), (args.length > 3 && (Boolean) args[3]),
(String) args[1], (String) args[1],
true); true
);
}
} }
} case "createSharedConsumer" -> {
else if (methodName.equals("createSharedConsumer")) { Destination dest = (Destination) args[0];
Destination dest = (Destination) args[0]; if (dest != null) {
if (dest != null) { return getCachedConsumer(
return getCachedConsumer(dest, dest,
(args.length > 2 ? (String) args[2] : null), (args.length > 2 ? (String) args[2] : null),
null, null,
(String) args[1], (String) args[1],
false); false
);
}
} }
} case "createSharedDurableConsumer" -> {
else if (methodName.equals("createSharedDurableConsumer")) { Destination dest = (Destination) args[0];
Destination dest = (Destination) args[0]; if (dest != null) {
if (dest != null) { return getCachedConsumer(
return getCachedConsumer(dest, dest,
(args.length > 2 ? (String) args[2] : null), (args.length > 2 ? (String) args[2] : null),
null, null,
(String) args[1], (String) args[1],
true); true
);
}
} }
} }
} }

View File

@ -378,10 +378,9 @@ public abstract class AbstractMethodMessageHandler<T>
*/ */
protected HandlerMethod createHandlerMethod(Object handler, Method method) { protected HandlerMethod createHandlerMethod(Object handler, Method method) {
HandlerMethod handlerMethod; HandlerMethod handlerMethod;
if (handler instanceof String) { if (handler instanceof String beanName) {
ApplicationContext context = getApplicationContext(); ApplicationContext context = getApplicationContext();
Assert.state(context != null, "ApplicationContext is required for resolving handler bean names"); Assert.state(context != null, "ApplicationContext is required for resolving handler bean names");
String beanName = (String) handler;
handlerMethod = new HandlerMethod(beanName, context.getAutowireCapableBeanFactory(), method); handlerMethod = new HandlerMethod(beanName, context.getAutowireCapableBeanFactory(), method);
} }
else { else {

View File

@ -93,10 +93,9 @@ public class GenericMessage<T> implements Message<T>, Serializable {
if (this == other) { if (this == other) {
return true; return true;
} }
if (!(other instanceof GenericMessage)) { if (!(other instanceof GenericMessage<?> otherMsg)) {
return false; return false;
} }
GenericMessage<?> otherMsg = (GenericMessage<?>) other;
// Using nullSafeEquals for proper array equals comparisons // Using nullSafeEquals for proper array equals comparisons
return (ObjectUtils.nullSafeEquals(this.payload, otherMsg.payload) && this.headers.equals(otherMsg.headers)); return (ObjectUtils.nullSafeEquals(this.payload, otherMsg.payload) && this.headers.equals(otherMsg.headers));
} }

View File

@ -617,8 +617,7 @@ public class MessageHeaderAccessor {
* @since 4.1 * @since 4.1
*/ */
public static MessageHeaderAccessor getMutableAccessor(Message<?> message) { public static MessageHeaderAccessor getMutableAccessor(Message<?> message) {
if (message.getHeaders() instanceof MutableMessageHeaders) { if (message.getHeaders() instanceof MutableMessageHeaders mutableHeaders) {
MutableMessageHeaders mutableHeaders = (MutableMessageHeaders) message.getHeaders();
MessageHeaderAccessor accessor = mutableHeaders.getAccessor(); MessageHeaderAccessor accessor = mutableHeaders.getAccessor();
return (accessor.isMutable() ? accessor : accessor.createAccessor(message)); return (accessor.isMutable() ? accessor : accessor.createAccessor(message));
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -62,13 +62,13 @@ public class ProtobufMessageConverterTests {
this.message = MessageBuilder.withPayload(this.testMsg.toByteArray()) this.message = MessageBuilder.withPayload(this.testMsg.toByteArray())
.setHeader(CONTENT_TYPE, ProtobufMessageConverter.PROTOBUF).build(); .setHeader(CONTENT_TYPE, ProtobufMessageConverter.PROTOBUF).build();
this.messageWithoutContentType = MessageBuilder.withPayload(this.testMsg.toByteArray()).build(); this.messageWithoutContentType = MessageBuilder.withPayload(this.testMsg.toByteArray()).build();
this.messageJson = MessageBuilder.withPayload( this.messageJson = MessageBuilder.withPayload("""
"{\n" + {
" \"foo\": \"Foo\",\n" + "foo": "Foo",
" \"blah\": {\n" + "blah": {
" \"blah\": 123\n" + "blah": 123
" }\n" + }
"}") }""".replace("\t", " "))
.setHeader(CONTENT_TYPE, APPLICATION_JSON) .setHeader(CONTENT_TYPE, APPLICATION_JSON)
.build(); .build();
} }

View File

@ -319,9 +319,7 @@ public class MessageHeaderAccessorTests {
})).isEqualTo(expected); })).isEqualTo(expected);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i = 0; i < 80; i++) { sb.append("a".repeat(80));
sb.append('a');
}
final String payload = sb.toString() + " > 80"; final String payload = sb.toString() + " > 80";
String actual = accessor.getShortLogMessage(payload); String actual = accessor.getShortLogMessage(payload);
@ -355,10 +353,8 @@ public class MessageHeaderAccessorTests {
})).isEqualTo(expected); })).isEqualTo(expected);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i = 0; i < 80; i++) { sb.append("a".repeat(80));
sb.append('a'); final String payload = sb + " > 80";
}
final String payload = sb.toString() + " > 80";
String actual = accessor.getDetailedLogMessage(payload); String actual = accessor.getDetailedLogMessage(payload);
assertThat(actual).isEqualTo("headers={contentType=text/plain} payload=" + sb + " > 80"); assertThat(actual).isEqualTo("headers={contentType=text/plain} payload=" + sb + " > 80");

View File

@ -362,11 +362,10 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
if (this.entityInterceptor instanceof Interceptor) { if (this.entityInterceptor instanceof Interceptor) {
return (Interceptor) this.entityInterceptor; return (Interceptor) this.entityInterceptor;
} }
else if (this.entityInterceptor instanceof String) { else if (this.entityInterceptor instanceof String beanName) {
if (this.beanFactory == null) { if (this.beanFactory == null) {
throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set"); throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
} }
String beanName = (String) this.entityInterceptor;
return this.beanFactory.getBean(beanName, Interceptor.class); return this.beanFactory.getBean(beanName, Interceptor.class);
} }
else { else {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -344,8 +344,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
if (getEntityManagerFactory() == null) { if (getEntityManagerFactory() == null) {
throw new IllegalArgumentException("'entityManagerFactory' or 'persistenceUnitName' is required"); throw new IllegalArgumentException("'entityManagerFactory' or 'persistenceUnitName' is required");
} }
if (getEntityManagerFactory() instanceof EntityManagerFactoryInfo) { if (getEntityManagerFactory() instanceof EntityManagerFactoryInfo emfInfo) {
EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) getEntityManagerFactory();
DataSource dataSource = emfInfo.getDataSource(); DataSource dataSource = emfInfo.getDataSource();
if (dataSource != null) { if (dataSource != null) {
setDataSource(dataSource); setDataSource(dataSource);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -107,21 +107,19 @@ class InfrastructureProxyTransactionalSqlScriptsTests extends AbstractTransactio
@Override @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) { return switch (method.getName()) {
case "equals": case "equals" -> (proxy == args[0]);
return (proxy == args[0]); case "hashCode" -> System.identityHashCode(proxy);
case "hashCode": case "getWrappedObject" -> this.dataSource;
return System.identityHashCode(proxy); default -> {
case "getWrappedObject":
return this.dataSource;
default:
try { try {
return method.invoke(this.dataSource, args); yield method.invoke(this.dataSource, args);
} }
catch (InvocationTargetException ex) { catch (InvocationTargetException ex) {
throw ex.getTargetException(); throw ex.getTargetException();
} }
} }
};
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -45,15 +45,13 @@ public class TransactionManagementConfigurationSelector extends AdviceModeImport
*/ */
@Override @Override
protected String[] selectImports(AdviceMode adviceMode) { protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) { return switch (adviceMode) {
case PROXY: case PROXY -> new String[]{
return new String[] {AutoProxyRegistrar.class.getName(), AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()}; ProxyTransactionManagementConfiguration.class.getName()
case ASPECTJ: };
return new String[] {determineTransactionAspectClass()}; case ASPECTJ -> new String[]{determineTransactionAspectClass()};
default: };
return null;
}
} }
private String determineTransactionAspectClass() { private String determineTransactionAspectClass() {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -56,12 +56,12 @@ public class TransactionAttributeSourceEditorTests {
@Test @Test
public void matchesSpecific() throws Exception { public void matchesSpecific() throws Exception {
editor.setAsText( editor.setAsText("""
"java.lang.Object.hashCode=PROPAGATION_REQUIRED\n" + java.lang.Object.hashCode=PROPAGATION_REQUIRED
"java.lang.Object.equals=PROPAGATION_MANDATORY\n" + java.lang.Object.equals=PROPAGATION_MANDATORY
"java.lang.Object.*it=PROPAGATION_SUPPORTS\n" + java.lang.Object.*it=PROPAGATION_SUPPORTS
"java.lang.Object.notify=PROPAGATION_SUPPORTS\n" + java.lang.Object.notify=PROPAGATION_SUPPORTS
"java.lang.Object.not*=PROPAGATION_REQUIRED"); java.lang.Object.not*=PROPAGATION_REQUIRED""");
TransactionAttributeSource tas = (TransactionAttributeSource) editor.getValue(); TransactionAttributeSource tas = (TransactionAttributeSource) editor.getValue();
checkTransactionProperties(tas, Object.class.getMethod("hashCode"), checkTransactionProperties(tas, Object.class.getMethod("hashCode"),

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -97,32 +97,26 @@ public class HttpServerErrorException extends HttpStatusCodeException {
String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) { String statusText, HttpHeaders headers, byte[] body, @Nullable Charset charset) {
if (statusCode instanceof HttpStatus status) { if (statusCode instanceof HttpStatus status) {
switch (status) { return switch (status) {
case INTERNAL_SERVER_ERROR: case INTERNAL_SERVER_ERROR -> message != null ?
return message != null ? new InternalServerError(message, statusText, headers, body, charset) :
new HttpServerErrorException.InternalServerError(message, statusText, headers, body, charset) : new InternalServerError(statusText, headers, body, charset);
new HttpServerErrorException.InternalServerError(statusText, headers, body, charset); case NOT_IMPLEMENTED -> message != null ?
case NOT_IMPLEMENTED: new NotImplemented(message, statusText, headers, body, charset) :
return message != null ? new NotImplemented(statusText, headers, body, charset);
new HttpServerErrorException.NotImplemented(message, statusText, headers, body, charset) : case BAD_GATEWAY -> message != null ?
new HttpServerErrorException.NotImplemented(statusText, headers, body, charset); new BadGateway(message, statusText, headers, body, charset) :
case BAD_GATEWAY: new BadGateway(statusText, headers, body, charset);
return message != null ? case SERVICE_UNAVAILABLE -> message != null ?
new HttpServerErrorException.BadGateway(message, statusText, headers, body, charset) : new ServiceUnavailable(message, statusText, headers, body, charset) :
new HttpServerErrorException.BadGateway(statusText, headers, body, charset); new ServiceUnavailable(statusText, headers, body, charset);
case SERVICE_UNAVAILABLE: case GATEWAY_TIMEOUT -> message != null ?
return message != null ? new GatewayTimeout(message, statusText, headers, body, charset) :
new HttpServerErrorException.ServiceUnavailable(message, statusText, headers, body, charset) : new GatewayTimeout(statusText, headers, body, charset);
new HttpServerErrorException.ServiceUnavailable(statusText, headers, body, charset); default -> message != null ?
case GATEWAY_TIMEOUT: new HttpServerErrorException(message, statusCode, statusText, headers, body, charset) :
return message != null ? new HttpServerErrorException(statusCode, statusText, headers, body, charset);
new HttpServerErrorException.GatewayTimeout(message, statusText, headers, body, charset) : };
new HttpServerErrorException.GatewayTimeout(statusText, headers, body, charset);
default:
return message != null ?
new HttpServerErrorException(message, statusCode, statusText, headers, body, charset) :
new HttpServerErrorException(statusCode, statusText, headers, body, charset);
}
} }
if (message != null) { if (message != null) {
return new HttpServerErrorException(message, statusCode, statusText, headers, body, charset); return new HttpServerErrorException(message, statusCode, statusText, headers, body, charset);

View File

@ -263,18 +263,14 @@ public class CorsConfiguration {
boolean withinPortRange = false; boolean withinPortRange = false;
for (int current = 0; current < rawValue.length(); current++) { for (int current = 0; current < rawValue.length(); current++) {
switch (rawValue.charAt(current)) { switch (rawValue.charAt(current)) {
case '[': case '[' -> withinPortRange = true;
withinPortRange = true; case ']' -> withinPortRange = false;
break; case ',' -> {
case ']':
withinPortRange = false;
break;
case ',':
if (!withinPortRange) { if (!withinPortRange) {
valueConsumer.accept(rawValue.substring(start, current).trim()); valueConsumer.accept(rawValue.substring(start, current).trim());
start = current + 1; start = current + 1;
} }
break; }
} }
} }
if (start < rawValue.length()) { if (start < rawValue.length()) {

View File

@ -159,8 +159,12 @@ public class ServerSentEventHttpMessageReaderTests extends AbstractLeakCheckingT
public void readPojo() { public void readPojo() {
MockServerHttpRequest request = MockServerHttpRequest.post("/") MockServerHttpRequest request = MockServerHttpRequest.post("/")
.body(Mono.just(stringBuffer( .body(Mono.just(stringBuffer(
"data:{\"foo\": \"foofoo\", \"bar\": \"barbar\"}\n\n" + """
"data:{\"foo\": \"foofoofoo\", \"bar\": \"barbarbar\"}\n\n"))); data:{"foo": "foofoo", "bar": "barbar"}
data:{"foo": "foofoofoo", "bar": "barbarbar"}
""")));
Flux<Pojo> data = reader.read(ResolvableType.forClass(Pojo.class), request, Flux<Pojo> data = reader.read(ResolvableType.forClass(Pojo.class), request,
Collections.emptyMap()).cast(Pojo.class); Collections.emptyMap()).cast(Pojo.class);

View File

@ -173,14 +173,18 @@ class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAllocating
StepVerifier.create(outputMessage.getBody()) StepVerifier.create(outputMessage.getBody())
.consumeNextWith(stringConsumer("data:")) .consumeNextWith(stringConsumer("data:"))
.consumeNextWith(stringConsumer("{\n" + .consumeNextWith(stringConsumer("""
"data: \"foo\" : \"foofoo\",\n" + {
"data: \"bar\" : \"barbar\"\n" + "data:}")) data: "foo" : "foofoo",
data: "bar" : "barbar"
data:}"""))
.consumeNextWith(stringConsumer("\n\n")) .consumeNextWith(stringConsumer("\n\n"))
.consumeNextWith(stringConsumer("data:")) .consumeNextWith(stringConsumer("data:"))
.consumeNextWith(stringConsumer("{\n" + .consumeNextWith(stringConsumer("""
"data: \"foo\" : \"foofoofoo\",\n" + {
"data: \"bar\" : \"barbarbar\"\n" + "data:}")) data: "foo" : "foofoofoo",
data: "bar" : "barbarbar"
data:}"""))
.consumeNextWith(stringConsumer("\n\n")) .consumeNextWith(stringConsumer("\n\n"))
.expectComplete() .expectComplete()
.verify(); .verify();

View File

@ -181,21 +181,22 @@ public class Jaxb2CollectionHttpMessageConverterTests {
public void testXmlBomb() throws Exception { public void testXmlBomb() throws Exception {
// https://en.wikipedia.org/wiki/Billion_laughs // https://en.wikipedia.org/wiki/Billion_laughs
// https://msdn.microsoft.com/en-us/magazine/ee335713.aspx // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx
String content = "<?xml version=\"1.0\"?>\n" + String content = """
"<!DOCTYPE lolz [\n" + <?xml version="1.0"?>
" <!ENTITY lol \"lol\">\n" + <!DOCTYPE lolz [
" <!ELEMENT lolz (#PCDATA)>\n" + <!ENTITY lol "lol">
" <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">\n" + <!ELEMENT lolz (#PCDATA)>
" <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">\n" + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
" <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">\n" + <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
" <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">\n" + <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
" <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">\n" + <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
" <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">\n" + <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
" <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">\n" + <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
" <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">\n" + <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
" <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">\n" + <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
"]>\n" + <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
"<list><rootElement><external>&lol9;</external></rootElement></list>"; ]>
<list><rootElement><external>&lol9;</external></rootElement></list>""";
MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8)); MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
assertThatExceptionOfType(HttpMessageNotReadableException.class) assertThatExceptionOfType(HttpMessageNotReadableException.class)
.isThrownBy(() -> this.converter.read(this.rootElementListType, null, inputMessage)) .isThrownBy(() -> this.converter.read(this.rootElementListType, null, inputMessage))

View File

@ -153,21 +153,22 @@ public class Jaxb2RootElementHttpMessageConverterTests {
public void testXmlBomb() throws Exception { public void testXmlBomb() throws Exception {
// https://en.wikipedia.org/wiki/Billion_laughs // https://en.wikipedia.org/wiki/Billion_laughs
// https://msdn.microsoft.com/en-us/magazine/ee335713.aspx // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx
String content = "<?xml version=\"1.0\"?>\n" + String content = """
"<!DOCTYPE lolz [\n" + <?xml version="1.0"?>
" <!ENTITY lol \"lol\">\n" + <!DOCTYPE lolz [
" <!ELEMENT lolz (#PCDATA)>\n" + <!ENTITY lol "lol">
" <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">\n" + <!ELEMENT lolz (#PCDATA)>
" <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">\n" + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
" <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">\n" + <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
" <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">\n" + <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
" <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">\n" + <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
" <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">\n" + <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
" <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">\n" + <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
" <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">\n" + <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
" <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">\n" + <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
"]>\n" + <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
"<rootElement><external>&lol9;</external></rootElement>"; ]>
<rootElement><external>&lol9;</external></rootElement>""";
MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8)); MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
assertThatExceptionOfType(HttpMessageNotReadableException.class).isThrownBy(() -> assertThatExceptionOfType(HttpMessageNotReadableException.class).isThrownBy(() ->
this.converter.read(RootElement.class, inputMessage)) this.converter.read(RootElement.class, inputMessage))

View File

@ -168,21 +168,22 @@ public class MappingJackson2XmlHttpMessageConverterTests {
public void readWithXmlBomb() throws IOException { public void readWithXmlBomb() throws IOException {
// https://en.wikipedia.org/wiki/Billion_laughs // https://en.wikipedia.org/wiki/Billion_laughs
// https://msdn.microsoft.com/en-us/magazine/ee335713.aspx // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx
String body = "<?xml version=\"1.0\"?>\n" + String body = """
"<!DOCTYPE lolz [\n" + <?xml version="1.0"?>
" <!ENTITY lol \"lol\">\n" + <!DOCTYPE lolz [
" <!ELEMENT lolz (#PCDATA)>\n" + <!ENTITY lol "lol">
" <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">\n" + <!ELEMENT lolz (#PCDATA)>
" <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">\n" + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
" <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">\n" + <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
" <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">\n" + <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
" <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">\n" + <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
" <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">\n" + <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
" <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">\n" + <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
" <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">\n" + <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
" <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">\n" + <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
"]>\n" + <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
"<MyBean>&lol9;</MyBean>"; ]>
<MyBean>&lol9;</MyBean>""";
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(StandardCharsets.UTF_8)); MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(StandardCharsets.UTF_8));
inputMessage.getHeaders().setContentType(MediaType.APPLICATION_XML); inputMessage.getHeaders().setContentType(MediaType.APPLICATION_XML);

View File

@ -112,21 +112,22 @@ public class SourceHttpMessageConverterTests {
public void readDomSourceWithXmlBomb() throws Exception { public void readDomSourceWithXmlBomb() throws Exception {
// https://en.wikipedia.org/wiki/Billion_laughs // https://en.wikipedia.org/wiki/Billion_laughs
// https://msdn.microsoft.com/en-us/magazine/ee335713.aspx // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx
String content = "<?xml version=\"1.0\"?>\n" + String content = """
"<!DOCTYPE lolz [\n" + <?xml version="1.0"?>
" <!ENTITY lol \"lol\">\n" + <!DOCTYPE lolz [
" <!ELEMENT lolz (#PCDATA)>\n" + <!ENTITY lol "lol">
" <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">\n" + <!ELEMENT lolz (#PCDATA)>
" <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">\n" + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
" <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">\n" + <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
" <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">\n" + <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
" <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">\n" + <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
" <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">\n" + <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
" <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">\n" + <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
" <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">\n" + <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
" <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">\n" + <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
"]>\n" + <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
"<root>&lol9;</root>"; ]>
<root>&lol9;</root>""";
MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8)); MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
assertThatExceptionOfType(HttpMessageNotReadableException.class).isThrownBy(() -> assertThatExceptionOfType(HttpMessageNotReadableException.class).isThrownBy(() ->
@ -166,21 +167,22 @@ public class SourceHttpMessageConverterTests {
public void readSAXSourceWithXmlBomb() throws Exception { public void readSAXSourceWithXmlBomb() throws Exception {
// https://en.wikipedia.org/wiki/Billion_laughs // https://en.wikipedia.org/wiki/Billion_laughs
// https://msdn.microsoft.com/en-us/magazine/ee335713.aspx // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx
String content = "<?xml version=\"1.0\"?>\n" + String content = """
"<!DOCTYPE lolz [\n" + <?xml version="1.0"?>
" <!ENTITY lol \"lol\">\n" + <!DOCTYPE lolz [
" <!ELEMENT lolz (#PCDATA)>\n" + <!ENTITY lol "lol">
" <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">\n" + <!ELEMENT lolz (#PCDATA)>
" <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">\n" + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
" <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">\n" + <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
" <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">\n" + <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
" <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">\n" + <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
" <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">\n" + <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
" <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">\n" + <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
" <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">\n" + <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
" <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">\n" + <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
"]>\n" + <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
"<root>&lol9;</root>"; ]>
<root>&lol9;</root>""";
MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8)); MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
SAXSource result = (SAXSource) this.converter.read(SAXSource.class, inputMessage); SAXSource result = (SAXSource) this.converter.read(SAXSource.class, inputMessage);
@ -232,21 +234,22 @@ public class SourceHttpMessageConverterTests {
public void readStAXSourceWithXmlBomb() throws Exception { public void readStAXSourceWithXmlBomb() throws Exception {
// https://en.wikipedia.org/wiki/Billion_laughs // https://en.wikipedia.org/wiki/Billion_laughs
// https://msdn.microsoft.com/en-us/magazine/ee335713.aspx // https://msdn.microsoft.com/en-us/magazine/ee335713.aspx
String content = "<?xml version=\"1.0\"?>\n" + String content = """
"<!DOCTYPE lolz [\n" + <?xml version="1.0"?>
" <!ENTITY lol \"lol\">\n" + <!DOCTYPE lolz [
" <!ELEMENT lolz (#PCDATA)>\n" + <!ENTITY lol "lol">
" <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">\n" + <!ELEMENT lolz (#PCDATA)>
" <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">\n" + <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
" <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">\n" + <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
" <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">\n" + <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
" <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">\n" + <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
" <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">\n" + <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
" <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">\n" + <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
" <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">\n" + <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
" <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">\n" + <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
"]>\n" + <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
"<root>&lol9;</root>"; ]>
<root>&lol9;</root>""";
MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8)); MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes(StandardCharsets.UTF_8));
StAXSource result = (StAXSource) this.converter.read(StAXSource.class, inputMessage); StAXSource result = (StAXSource) this.converter.read(StAXSource.class, inputMessage);

View File

@ -84,11 +84,13 @@ public class StandardMultipartHttpServletRequestTests {
new FormHttpMessageConverter().write(map, null, output); new FormHttpMessageConverter().write(map, null, output);
assertThat(output.getBodyAsString(StandardCharsets.UTF_8)).contains( assertThat(output.getBodyAsString(StandardCharsets.UTF_8)).contains(
"Content-Disposition: form-data; name=\"file\"; filename=\"myFile.txt\"\r\n" + """
"Content-Type: text/plain\r\n" + Content-Disposition: form-data; name="file"; filename="myFile.txt"\r
"Content-Length: 6\r\n" + Content-Type: text/plain\r
"\r\n" + Content-Length: 6\r
"myBody\r\n"); \r
myBody\r
""");
} }

View File

@ -201,34 +201,22 @@ public final class CloseStatus {
*/ */
public static CloseStatus create(int code, @Nullable String reason) { public static CloseStatus create(int code, @Nullable String reason) {
if (!StringUtils.hasText(reason)) { if (!StringUtils.hasText(reason)) {
switch (code) { return switch (code) {
case 1000: case 1000 -> NORMAL;
return NORMAL; case 1001 -> GOING_AWAY;
case 1001: case 1002 -> PROTOCOL_ERROR;
return GOING_AWAY; case 1003 -> NOT_ACCEPTABLE;
case 1002: case 1005 -> NO_STATUS_CODE;
return PROTOCOL_ERROR; case 1006 -> NO_CLOSE_FRAME;
case 1003: case 1007 -> BAD_DATA;
return NOT_ACCEPTABLE; case 1008 -> POLICY_VIOLATION;
case 1005: case 1009 -> TOO_BIG_TO_PROCESS;
return NO_STATUS_CODE; case 1010 -> REQUIRED_EXTENSION;
case 1006: case 1011 -> SERVER_ERROR;
return NO_CLOSE_FRAME; case 1012 -> SERVICE_RESTARTED;
case 1007: case 1013 -> SERVICE_OVERLOAD;
return BAD_DATA; default -> new CloseStatus(code, reason);
case 1008: };
return POLICY_VIOLATION;
case 1009:
return TOO_BIG_TO_PROCESS;
case 1010:
return REQUIRED_EXTENSION;
case 1011:
return SERVER_ERROR;
case 1012:
return SERVICE_RESTARTED;
case 1013:
return SERVICE_OVERLOAD;
}
} }
return new CloseStatus(code, reason); return new CloseStatus(code, reason);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -125,26 +125,20 @@ class FlushingIntegrationTests extends AbstractHttpHandlerIntegrationTests {
@Override @Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) { public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
String path = request.getURI().getPath(); String path = request.getURI().getPath();
switch (path) { return switch (path) {
case "/write-and-flush": case "/write-and-flush" -> response.writeAndFlushWith(
return response.writeAndFlushWith( testInterval(Duration.ofMillis(50), 2)
testInterval(Duration.ofMillis(50), 2) .map(longValue -> wrap("data" + longValue + "\n", response))
.map(longValue -> wrap("data" + longValue + "\n", response)) .map(Flux::just)
.map(Flux::just) .mergeWith(Flux.never()));
.mergeWith(Flux.never())); case "/write-and-complete" -> response.writeWith(
chunks1K().take(64).map(s -> wrap(s, response)));
case "/write-and-complete": case "/write-and-never-complete" ->
return response.writeWith(
chunks1K().take(64).map(s -> wrap(s, response)));
case "/write-and-never-complete":
// Reactor requires at least 50 to flush, Tomcat/Undertow 8, Jetty 1 // Reactor requires at least 50 to flush, Tomcat/Undertow 8, Jetty 1
return response.writeWith( response.writeWith(
chunks1K().take(64).map(s -> wrap(s, response)).mergeWith(Flux.never())); chunks1K().take(64).map(s -> wrap(s, response)).mergeWith(Flux.never()));
default -> response.writeWith(Flux.empty());
default: };
return response.writeWith(Flux.empty());
}
} }
private Flux<String> chunks1K() { private Flux<String> chunks1K() {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -336,23 +336,25 @@ public class BodyExtractorsTests {
public void toParts() { public void toParts() {
BodyExtractor<Flux<Part>, ServerHttpRequest> extractor = BodyExtractors.toParts(); BodyExtractor<Flux<Part>, ServerHttpRequest> extractor = BodyExtractors.toParts();
String bodyContents = "-----------------------------9051914041544843365972754266\r\n" + String bodyContents = """
"Content-Disposition: form-data; name=\"text\"\r\n" + -----------------------------9051914041544843365972754266\r
"\r\n" + Content-Disposition: form-data; name="text"\r
"text default\r\n" + \r
"-----------------------------9051914041544843365972754266\r\n" + text default\r
"Content-Disposition: form-data; name=\"file1\"; filename=\"a.txt\"\r\n" + -----------------------------9051914041544843365972754266\r
"Content-Type: text/plain\r\n" + Content-Disposition: form-data; name="file1"; filename="a.txt"\r
"\r\n" + Content-Type: text/plain\r
"Content of a.txt.\r\n" + \r
"\r\n" + Content of a.txt.\r
"-----------------------------9051914041544843365972754266\r\n" + \r
"Content-Disposition: form-data; name=\"file2\"; filename=\"a.html\"\r\n" + -----------------------------9051914041544843365972754266\r
"Content-Type: text/html\r\n" + Content-Disposition: form-data; name="file2"; filename="a.html"\r
"\r\n" + Content-Type: text/html\r
"<!DOCTYPE html><title>Content of a.html.</title>\r\n" + \r
"\r\n" + <!DOCTYPE html><title>Content of a.html.</title>\r
"-----------------------------9051914041544843365972754266--\r\n"; \r
-----------------------------9051914041544843365972754266--\r
""";
byte[] bytes = bodyContents.getBytes(StandardCharsets.UTF_8); byte[] bytes = bodyContents.getBytes(StandardCharsets.UTF_8);
DefaultDataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(ByteBuffer.wrap(bytes)); DefaultDataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(ByteBuffer.wrap(bytes));

View File

@ -726,8 +726,8 @@ class WebClientIntegrationTests {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
try { try {
request.getBody().copyTo(bos); request.getBody().copyTo(bos);
String actual = bos.toString("UTF-8"); String actual = bos.toString(StandardCharsets.UTF_8);
String expected = new String(Files.readAllBytes(resource.getFile().toPath()), StandardCharsets.UTF_8); String expected = Files.readString(resource.getFile().toPath(), StandardCharsets.UTF_8);
assertThat(actual).isEqualTo(expected); assertThat(actual).isEqualTo(expected);
} }
catch (IOException ex) { catch (IOException ex) {

View File

@ -412,15 +412,17 @@ public class DefaultServerRequestTests {
@Test @Test
public void multipartData() { public void multipartData() {
String data = "--12345\r\n" + String data = """
"Content-Disposition: form-data; name=\"foo\"\r\n" + --12345\r
"\r\n" + Content-Disposition: form-data; name="foo"\r
"bar\r\n" + \r
"--12345\r\n" + bar\r
"Content-Disposition: form-data; name=\"baz\"\r\n" + --12345\r
"\r\n" + Content-Disposition: form-data; name="baz"\r
"qux\r\n" + \r
"--12345--\r\n"; qux\r
--12345--\r
""";
byte[] bytes = data.getBytes(StandardCharsets.UTF_8); byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
DefaultDataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(ByteBuffer.wrap(bytes)); DefaultDataBuffer dataBuffer = DefaultDataBufferFactory.sharedInstance.wrap(ByteBuffer.wrap(bytes));
Flux<DataBuffer> body = Flux.just(dataBuffer); Flux<DataBuffer> body = Flux.just(dataBuffer);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -80,13 +80,17 @@ public class CssLinkResourceTransformerTests {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/main.css")); MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/main.css"));
Resource css = getResource("main.css"); Resource css = getResource("main.css");
String expected = "\n" + String expected = """
"@import url(\"/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix\");\n" +
"@import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');\n" + @import url("/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix");
"@import url(/static/bar-11e16cf79faee7ac698c805cf28248d2.css);\n\n" + @import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');
"@import \"/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css\";\n" + @import url(/static/bar-11e16cf79faee7ac698c805cf28248d2.css);
"@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\n" +
"body { background: url(\"/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix\") }\n"; @import "/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css";
@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';
body { background: url("/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix") }
""";
StepVerifier.create(this.transformerChain.transform(exchange, css) StepVerifier.create(this.transformerChain.transform(exchange, css)
.cast(TransformedResource.class)) .cast(TransformedResource.class))
@ -118,9 +122,10 @@ public class CssLinkResourceTransformerTests {
ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers); ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers);
Resource resource = getResource("external.css"); Resource resource = getResource("external.css");
String expected = "@import url(\"https://example.org/fonts/css\");\n" + String expected = """
"body { background: url(\"file:///home/spring/image.png\") }\n" + @import url("https://example.org/fonts/css");
"figure { background: url(\"//example.org/style.css\")}"; body { background: url("file:///home/spring/image.png") }
figure { background: url("//example.org/style.css")}""";
StepVerifier.create(chain.transform(exchange, resource) StepVerifier.create(chain.transform(exchange, resource)
.cast(TransformedResource.class)) .cast(TransformedResource.class))
@ -167,10 +172,10 @@ public class CssLinkResourceTransformerTests {
public void transformEmptyUrlFunction() throws Exception { public void transformEmptyUrlFunction() throws Exception {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/empty_url_function.css")); MockServerWebExchange exchange = MockServerWebExchange.from(get("/static/empty_url_function.css"));
Resource css = getResource("empty_url_function.css"); Resource css = getResource("empty_url_function.css");
String expected = String expected = """
".fooStyle {\n" + .fooStyle {
"\tbackground: transparent url() no-repeat left top;\n" + \tbackground: transparent url() no-repeat left top;
"}"; }""";
StepVerifier.create(this.transformerChain.transform(exchange, css) StepVerifier.create(this.transformerChain.transform(exchange, css)
.cast(TransformedResource.class)) .cast(TransformedResource.class))

View File

@ -45,7 +45,6 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.server.MockServerWebExchange; import org.springframework.web.testfixture.server.MockServerWebExchange;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -357,8 +356,9 @@ public class FreeMarkerMacroTests {
} }
private void storeTemplateInTempDir(String macro) throws IOException { private void storeTemplateInTempDir(String macro) throws IOException {
Files.write(this.templateLoaderPath.resolve("tmp.ftl"), Files.writeString(this.templateLoaderPath.resolve("tmp.ftl"),
("<#import \"spring.ftl\" as spring />\n" + macro).getBytes(UTF_8)); "<#import \"spring.ftl\" as spring />\n" + macro
);
} }
private List<String> getOutput() { private List<String> getOutput() {

View File

@ -381,8 +381,7 @@ class ReactiveTypeHandler {
@Override @Override
protected void send(Object element) throws IOException { protected void send(Object element) throws IOException {
if (element instanceof ServerSentEvent) { if (element instanceof ServerSentEvent<?> event) {
ServerSentEvent<?> event = (ServerSentEvent<?>) element;
((SseEmitter) getEmitter()).send(adapt(event)); ((SseEmitter) getEmitter()).send(adapt(event));
} }
else { else {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -223,16 +223,14 @@ public abstract class AbstractMultiCheckedElementTag extends AbstractCheckedElem
writeObjectEntry(tagWriter, valueProperty, labelProperty, item, i); writeObjectEntry(tagWriter, valueProperty, labelProperty, item, i);
} }
} }
else if (itemsObject instanceof Collection) { else if (itemsObject instanceof final Collection<?> optionCollection) {
final Collection<?> optionCollection = (Collection<?>) itemsObject;
int itemIndex = 0; int itemIndex = 0;
for (Iterator<?> it = optionCollection.iterator(); it.hasNext(); itemIndex++) { for (Iterator<?> it = optionCollection.iterator(); it.hasNext(); itemIndex++) {
Object item = it.next(); Object item = it.next();
writeObjectEntry(tagWriter, valueProperty, labelProperty, item, itemIndex); writeObjectEntry(tagWriter, valueProperty, labelProperty, item, itemIndex);
} }
} }
else if (itemsObject instanceof Map) { else if (itemsObject instanceof final Map<?, ?> optionMap) {
final Map<?, ?> optionMap = (Map<?, ?>) itemsObject;
int itemIndex = 0; int itemIndex = 0;
for (Iterator it = optionMap.entrySet().iterator(); it.hasNext(); itemIndex++) { for (Iterator it = optionMap.entrySet().iterator(); it.hasNext(); itemIndex++) {
Map.Entry entry = (Map.Entry) it.next(); Map.Entry entry = (Map.Entry) it.next();

View File

@ -537,8 +537,7 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView {
} }
return true; return true;
} }
if (value instanceof Collection) { if (value instanceof Collection<?> coll) {
Collection<?> coll = (Collection<?>) value;
if (coll.isEmpty()) { if (coll.isEmpty()) {
return false; return false;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -109,12 +109,15 @@ class SseServerResponseTests {
ModelAndView mav = response.writeTo(this.mockRequest, this.mockResponse, context); ModelAndView mav = response.writeTo(this.mockRequest, this.mockResponse, context);
assertThat(mav).isNull(); assertThat(mav).isNull();
String expected = "id:id\n" + String expected = """
"event:name\n" + id:id
":comment line 1\n" + event:name
":comment line 2\n" + :comment line 1
"retry:1000\n" + :comment line 2
"data:data\n\n"; retry:1000
data:data
""";
assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected); assertThat(this.mockResponse.getContentAsString()).isEqualTo(expected);
} }

View File

@ -52,11 +52,12 @@ public class ToStringVisitorTests {
routerFunction.accept(visitor); routerFunction.accept(visitor);
String result = visitor.toString(); String result = visitor.toString();
String expected = "/foo => {\n" + String expected = """
" /bar => {\n" + /foo => {
" (GET && /baz) -> \n" + /bar => {
" }\n" + (GET && /baz) ->\s
"}"; }
}""".replace('\t', ' ');
assertThat(result).isEqualTo(expected); assertThat(result).isEqualTo(expected);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -84,13 +84,17 @@ public class CssLinkResourceTransformerTests {
public void transform() throws Exception { public void transform() throws Exception {
this.request = new MockHttpServletRequest("GET", "/static/main.css"); this.request = new MockHttpServletRequest("GET", "/static/main.css");
Resource css = getResource("main.css"); Resource css = getResource("main.css");
String expected = "\n" + String expected = """
"@import url(\"/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix\");\n" +
"@import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');\n" + @import url("/static/bar-11e16cf79faee7ac698c805cf28248d2.css?#iefix");
"@import url(/static/bar-11e16cf79faee7ac698c805cf28248d2.css);\n\n" + @import url('/static/bar-11e16cf79faee7ac698c805cf28248d2.css#bla-normal');
"@import \"/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css\";\n" + @import url(/static/bar-11e16cf79faee7ac698c805cf28248d2.css);
"@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';\n\n" +
"body { background: url(\"/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix\") }\n"; @import "/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css";
@import '/static/foo-e36d2e05253c6c7085a91522ce43a0b4.css';
body { background: url("/static/images/image-f448cd1d5dba82b774f3202c878230b3.png?#iefix") }
""";
TransformedResource actual = (TransformedResource) this.transformerChain.transform(this.request, css); TransformedResource actual = (TransformedResource) this.transformerChain.transform(this.request, css);
String result = new String(actual.getByteArray(), StandardCharsets.UTF_8); String result = new String(actual.getByteArray(), StandardCharsets.UTF_8);
@ -115,9 +119,10 @@ public class CssLinkResourceTransformerTests {
ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers); ResourceTransformerChain chain = new DefaultResourceTransformerChain(mockChain, transformers);
Resource resource = getResource("external.css"); Resource resource = getResource("external.css");
String expected = "@import url(\"https://example.org/fonts/css\");\n" + String expected = """
"body { background: url(\"file:///home/spring/image.png\") }\n" + @import url("https://example.org/fonts/css");
"figure { background: url(\"//example.org/style.css\")}"; body { background: url("file:///home/spring/image.png") }
figure { background: url("//example.org/style.css")}""";
TransformedResource transformedResource = (TransformedResource) chain.transform(this.request, resource); TransformedResource transformedResource = (TransformedResource) chain.transform(this.request, resource);
String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8); String result = new String(transformedResource.getByteArray(), StandardCharsets.UTF_8);
@ -155,10 +160,10 @@ public class CssLinkResourceTransformerTests {
public void transformEmptyUrlFunction() throws Exception { public void transformEmptyUrlFunction() throws Exception {
this.request = new MockHttpServletRequest("GET", "/static/empty_url_function.css"); this.request = new MockHttpServletRequest("GET", "/static/empty_url_function.css");
Resource css = getResource("empty_url_function.css"); Resource css = getResource("empty_url_function.css");
String expected = String expected = """
".fooStyle {\n" + .fooStyle {
"\tbackground: transparent url() no-repeat left top;\n" + \tbackground: transparent url() no-repeat left top;
"}"; }""";
TransformedResource actual = (TransformedResource) this.transformerChain.transform(this.request, css); TransformedResource actual = (TransformedResource) this.transformerChain.transform(this.request, css);
String result = new String(actual.getByteArray(), StandardCharsets.UTF_8); String result = new String(actual.getByteArray(), StandardCharsets.UTF_8);

View File

@ -48,7 +48,6 @@ import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
import org.springframework.web.testfixture.servlet.MockHttpServletResponse; import org.springframework.web.testfixture.servlet.MockHttpServletResponse;
import org.springframework.web.testfixture.servlet.MockServletContext; import org.springframework.web.testfixture.servlet.MockServletContext;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
@ -346,8 +345,9 @@ public class FreeMarkerMacroTests {
} }
private void storeTemplateInTempDir(String macro) throws IOException { private void storeTemplateInTempDir(String macro) throws IOException {
Files.write(this.templateLoaderPath.resolve("tmp.ftl"), Files.writeString(this.templateLoaderPath.resolve("tmp.ftl"),
("<#import \"spring.ftl\" as spring />\n" + macro).getBytes(UTF_8)); "<#import \"spring.ftl\" as spring />\n" + macro
);
} }
private String getOutput() throws IOException { private String getOutput() throws IOException {

View File

@ -427,7 +427,7 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void handleMessageToClient(WebSocketSession session, Message<?> message) { public void handleMessageToClient(WebSocketSession session, Message<?> message) {
if (!(message.getPayload() instanceof byte[])) { if (!(message.getPayload() instanceof byte[] payload)) {
if (logger.isErrorEnabled()) { if (logger.isErrorEnabled()) {
logger.error("Expected byte[] payload. Ignoring " + message + "."); logger.error("Expected byte[] payload. Ignoring " + message + ".");
} }
@ -464,7 +464,6 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
} }
} }
byte[] payload = (byte[]) message.getPayload();
if (StompCommand.ERROR.equals(command) && getErrorHandler() != null) { if (StompCommand.ERROR.equals(command) && getErrorHandler() != null) {
Message<byte[]> errorMessage = getErrorHandler().handleErrorMessageToClient((Message<byte[]>) message); Message<byte[]> errorMessage = getErrorHandler().handleErrorMessageToClient((Message<byte[]>) message);
if (errorMessage != null) { if (errorMessage != null) {

View File

@ -229,19 +229,14 @@ public abstract class AbstractClientSockJsSession implements WebSocketSession {
public void handleFrame(String payload) { public void handleFrame(String payload) {
SockJsFrame frame = new SockJsFrame(payload); SockJsFrame frame = new SockJsFrame(payload);
switch (frame.getType()) { switch (frame.getType()) {
case OPEN: case OPEN -> handleOpenFrame();
handleOpenFrame(); case HEARTBEAT -> {
break;
case HEARTBEAT:
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Received heartbeat in " + this); logger.trace("Received heartbeat in " + this);
} }
break; }
case MESSAGE: case MESSAGE -> handleMessageFrame(frame);
handleMessageFrame(frame); case CLOSE -> handleCloseFrame(frame);
break;
case CLOSE:
handleCloseFrame(frame);
} }
} }

View File

@ -276,12 +276,11 @@ public class TransportHandlingSockJsService extends AbstractSockJsService implem
SockJsSession session = this.sessions.get(sessionId); SockJsSession session = this.sessions.get(sessionId);
boolean isNewSession = false; boolean isNewSession = false;
if (session == null) { if (session == null) {
if (transportHandler instanceof SockJsSessionFactory) { if (transportHandler instanceof SockJsSessionFactory sessionFactory) {
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
if (!chain.applyBeforeHandshake(request, response, attributes)) { if (!chain.applyBeforeHandshake(request, response, attributes)) {
return; return;
} }
SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler;
session = createSockJsSession(sessionId, sessionFactory, handler, attributes); session = createSockJsSession(sessionId, sessionFactory, handler, attributes);
isNewSession = true; isNewSession = true;
} }