diff --git a/spring-core/src/main/java/org/springframework/core/convert/support/ObjectToOptionalConverter.java b/spring-core/src/main/java/org/springframework/core/convert/support/ObjectToOptionalConverter.java index 49b3df34c0..a41f519037 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/support/ObjectToOptionalConverter.java +++ b/spring-core/src/main/java/org/springframework/core/convert/support/ObjectToOptionalConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -29,7 +29,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter; import org.springframework.util.CollectionUtils; /** - * Convert an Object to {@code java.util.Optional} if necessary using the + * Convert an Object to a {@code java.util.Optional}, if necessary using the * {@code ConversionService} to convert the source Object to the generic type * of Optional when known. * diff --git a/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java index f1b35cc7c0..b50c793a88 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/converter/DefaultConversionServiceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -44,6 +44,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.core.MethodParameter; @@ -948,29 +949,44 @@ class DefaultConversionServiceTests { assertThat(converted).containsExactly(2, 3, 4); } - @Test - @SuppressWarnings("unchecked") - void convertObjectToOptional() { - Method method = ClassUtils.getMethod(TestEntity.class, "handleOptionalValue", Optional.class); - MethodParameter parameter = new MethodParameter(method, 0); - TypeDescriptor descriptor = new TypeDescriptor(parameter); - Object actual = conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class), descriptor); - assertThat(actual.getClass()).isEqualTo(Optional.class); - assertThat(((Optional>) actual)).contains(List.of(1, 2, 3)); - } - @Test - void convertObjectToOptionalNull() { - assertThat(conversionService.convert(null, TypeDescriptor.valueOf(Object.class), - TypeDescriptor.valueOf(Optional.class))).isSameAs(Optional.empty()); - assertThat((Object) conversionService.convert(null, Optional.class)).isSameAs(Optional.empty()); - } + @Nested + class OptionalConversionTests { - @Test - void convertExistingOptional() { - assertThat(conversionService.convert(Optional.empty(), TypeDescriptor.valueOf(Object.class), - TypeDescriptor.valueOf(Optional.class))).isSameAs(Optional.empty()); - assertThat((Object) conversionService.convert(Optional.empty(), Optional.class)).isSameAs(Optional.empty()); + private static final TypeDescriptor rawOptionalType = TypeDescriptor.valueOf(Optional.class); + + + @Test + @SuppressWarnings("unchecked") + void convertObjectToOptional() { + Method method = ClassUtils.getMethod(getClass(), "handleOptionalList", Optional.class); + MethodParameter parameter = new MethodParameter(method, 0); + TypeDescriptor descriptor = new TypeDescriptor(parameter); + Object actual = conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class), descriptor); + assertThat(((Optional>) actual)).contains(List.of(1, 2, 3)); + } + + @Test + void convertNullToOptional() { + assertThat((Object) conversionService.convert(null, Optional.class)).isSameAs(Optional.empty()); + assertThat(conversionService.convert(null, TypeDescriptor.valueOf(Object.class), rawOptionalType)) + .isSameAs(Optional.empty()); + } + + @Test + void convertNullOptionalToNull() { + assertThat(conversionService.convert(null, rawOptionalType, TypeDescriptor.valueOf(Object.class))).isNull(); + } + + @Test + void convertEmptyOptionalToOptional() { + assertThat((Object) conversionService.convert(Optional.empty(), Optional.class)).isSameAs(Optional.empty()); + assertThat(conversionService.convert(Optional.empty(), TypeDescriptor.valueOf(Object.class), rawOptionalType)) + .isSameAs(Optional.empty()); + } + + public void handleOptionalList(Optional> value) { + } } @@ -1068,9 +1084,6 @@ class DefaultConversionServiceTests { public static TestEntity findTestEntity(Long id) { return new TestEntity(id); } - - public void handleOptionalValue(Optional> value) { - } }