Browse Source

Polishing.

Fix nullability issues.

See #2217

(cherry picked from commit 08c86dc94e)
pull/2219/head
Mark Paluch 3 weeks ago committed by 62hoon99
parent
commit
73ff9cc2e3
  1. 7
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/IterableOfEntryToMapConverter.java
  2. 7
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java
  3. 41
      spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/convert/R2dbcConverters.java
  4. 5
      spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/dialect/MySqlDialect.java
  5. 45
      spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java
  6. 11
      spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/TypedSubtreeVisitor.java

7
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/IterableOfEntryToMapConverter.java

@ -19,7 +19,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalConverter; import org.springframework.core.convert.converter.ConditionalConverter;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
@ -32,16 +31,14 @@ import org.springframework.util.Assert;
*/ */
class IterableOfEntryToMapConverter implements ConditionalConverter, Converter<Iterable<?>, Map<?, ?>> { class IterableOfEntryToMapConverter implements ConditionalConverter, Converter<Iterable<?>, Map<?, ?>> {
@SuppressWarnings("unchecked")
@Nullable
@Override @Override
public Map<?, ?> convert(Iterable<?> source) { public Map<?, ?> convert(Iterable<?> source) {
Map result = new HashMap(); Map<Object, Object> result = new HashMap<>();
source.forEach(element -> { source.forEach(element -> {
if (element instanceof Entry entry) { if (element instanceof Entry<?, ?> entry) {
result.put(entry.getKey(), entry.getValue()); result.put(entry.getKey(), entry.getValue());
return; return;
} }

7
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/MappingJdbcConverter.java

@ -200,8 +200,7 @@ public class MappingJdbcConverter extends MappingRelationalConverter implements
* @return * @return
*/ */
@Override @Override
@Nullable public @Nullable Object readValue(@Nullable Object value, TypeInformation<?> targetType) {
public Object readValue(@Nullable Object value, TypeInformation<?> targetType) {
if (null == value) { if (null == value) {
return null; return null;
@ -573,12 +572,12 @@ public class MappingJdbcConverter extends MappingRelationalConverter implements
Identifier identifier) implements ConversionContext { Identifier identifier) implements ConversionContext {
@Override @Override
public <S> S convert(Object source, TypeInformation<? extends S> typeHint) { public <S> @Nullable S convert(Object source, TypeInformation<? extends S> typeHint) {
return delegate.convert(source, typeHint); return delegate.convert(source, typeHint);
} }
@Override @Override
public <S> S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context) { public <S> @Nullable S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context) {
return delegate.convert(source, typeHint, context); return delegate.convert(source, typeHint, context);
} }

41
spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/convert/R2dbcConverters.java

@ -70,12 +70,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToBooleanConverter implements Converter<Row, Boolean> { public enum RowToBooleanConverter implements Converter<Row, @Nullable Boolean> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable Boolean convert(Row row) { public Boolean convert(Row row) {
return row.get(0, Boolean.class); return row.get(0, Boolean.class);
} }
} }
@ -85,12 +85,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToLocalDateConverter implements Converter<Row, LocalDate> { public enum RowToLocalDateConverter implements Converter<Row, @Nullable LocalDate> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable LocalDate convert(Row row) { public LocalDate convert(Row row) {
return row.get(0, LocalDate.class); return row.get(0, LocalDate.class);
} }
} }
@ -100,12 +100,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToLocalDateTimeConverter implements Converter<Row, LocalDateTime> { public enum RowToLocalDateTimeConverter implements Converter<Row, @Nullable LocalDateTime> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable LocalDateTime convert(Row row) { public LocalDateTime convert(Row row) {
return row.get(0, LocalDateTime.class); return row.get(0, LocalDateTime.class);
} }
} }
@ -115,12 +115,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToLocalTimeConverter implements Converter<Row, LocalTime> { public enum RowToLocalTimeConverter implements Converter<Row, @Nullable LocalTime> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable LocalTime convert(Row row) { public LocalTime convert(Row row) {
return row.get(0, LocalTime.class); return row.get(0, LocalTime.class);
} }
} }
@ -141,20 +141,21 @@ abstract class R2dbcConverters {
* @see java.math.BigDecimal * @see java.math.BigDecimal
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToNumberConverterFactory implements ConverterFactory<Row, Number> { public enum RowToNumberConverterFactory implements ConverterFactory<Row, @Nullable Number> {
INSTANCE; INSTANCE;
@Override @Override
public <T extends Number> Converter<Row, T> getConverter(Class<T> targetType) { public <T extends @Nullable Number> Converter<Row, T> getConverter(Class<T> targetType) {
Assert.notNull(targetType, "Target type must not be null"); Assert.notNull(targetType, "Target type must not be null");
return new RowToNumber<>(targetType); return new RowToNumber<>(targetType);
} }
record RowToNumber<T extends Number>(Class<T> targetType) implements Converter<Row, T> { @SuppressWarnings("NullAway")
record RowToNumber<T extends @Nullable Number>(Class<T> targetType) implements Converter<Row, @Nullable T> {
@Override @Override
public @Nullable T convert(Row source) { public T convert(Row source) {
Object object = source.get(0); Object object = source.get(0);
@ -168,12 +169,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToOffsetDateTimeConverter implements Converter<Row, OffsetDateTime> { public enum RowToOffsetDateTimeConverter implements Converter<Row, @Nullable OffsetDateTime> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable OffsetDateTime convert(Row row) { public OffsetDateTime convert(Row row) {
return row.get(0, OffsetDateTime.class); return row.get(0, OffsetDateTime.class);
} }
} }
@ -183,12 +184,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToStringConverter implements Converter<Row, String> { public enum RowToStringConverter implements Converter<Row, @Nullable String> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable String convert(Row row) { public String convert(Row row) {
return row.get(0, String.class); return row.get(0, String.class);
} }
} }
@ -198,12 +199,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToUuidConverter implements Converter<Row, UUID> { public enum RowToUuidConverter implements Converter<Row, @Nullable UUID> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable UUID convert(Row row) { public UUID convert(Row row) {
return row.get(0, UUID.class); return row.get(0, UUID.class);
} }
} }
@ -213,12 +214,12 @@ abstract class R2dbcConverters {
* *
* @author Hebert Coelho * @author Hebert Coelho
*/ */
public enum RowToZonedDateTimeConverter implements Converter<Row, ZonedDateTime> { public enum RowToZonedDateTimeConverter implements Converter<Row, @Nullable ZonedDateTime> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable ZonedDateTime convert(Row row) { public ZonedDateTime convert(Row row) {
return row.get(0, ZonedDateTime.class); return row.get(0, ZonedDateTime.class);
} }
} }

5
spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/dialect/MySqlDialect.java

@ -80,12 +80,13 @@ public class MySqlDialect extends org.springframework.data.relational.core.diale
* @author Michael Berry * @author Michael Berry
*/ */
@ReadingConverter @ReadingConverter
public enum ByteToBooleanConverter implements Converter<Byte, Boolean> { @SuppressWarnings("NullAway")
public enum ByteToBooleanConverter implements Converter<Byte, @Nullable Boolean> {
INSTANCE; INSTANCE;
@Override @Override
public @Nullable Boolean convert(@Nullable Byte s) { public Boolean convert(@Nullable Byte s) {
if (s == null) { if (s == null) {
return null; return null;

45
spring-data-relational/src/main/java/org/springframework/data/relational/core/conversion/MappingRelationalConverter.java

@ -352,9 +352,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
if (getConversions().hasCustomReadTarget(RowDocument.class, rawType)) { if (getConversions().hasCustomReadTarget(RowDocument.class, rawType)) {
S converted = doConvert(documentAccessor.getDocument(), rawType, typeHint.getType()); S converted = doConvert(documentAccessor.getDocument(), rawType, typeHint.getType());
Assert.state(converted != null, "Converted must not be null"); Assert.state(converted != null, "Converted must not be null");
return converted; return converted;
} }
@ -363,7 +361,10 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
} }
if (typeHint.isMap()) { if (typeHint.isMap()) {
return context.convert(documentAccessor, typeHint);
S converted = context.convert(documentAccessor, typeHint);
Assert.state(converted != null, "Converted must not be null");
return converted;
} }
RelationalPersistentEntity<?> entity = getMappingContext().getPersistentEntity(typeHint); RelationalPersistentEntity<?> entity = getMappingContext().getPersistentEntity(typeHint);
@ -425,7 +426,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
* @param targetType the {@link Map} {@link TypeInformation} to be used to unmarshall this {@link RowDocument}. * @param targetType the {@link Map} {@link TypeInformation} to be used to unmarshall this {@link RowDocument}.
* @return the converted {@link Collection} or array, will never be {@literal null}. * @return the converted {@link Collection} or array, will never be {@literal null}.
*/ */
protected @Nullable Object readCollectionOrArray(ConversionContext context, Collection<?> source, protected Object readCollectionOrArray(ConversionContext context, Collection<?> source,
TypeInformation<?> targetType) { TypeInformation<?> targetType) {
Assert.notNull(targetType, "Target type must not be null"); Assert.notNull(targetType, "Target type must not be null");
@ -444,14 +445,14 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
: CollectionFactory.createCollection(collectionType, rawComponentType, source.size()); : CollectionFactory.createCollection(collectionType, rawComponentType, source.size());
if (source.isEmpty()) { if (source.isEmpty()) {
return getPotentiallyConvertedSimpleRead(items, targetType); return getRequiredPotentiallyConvertedSimpleRead(items, targetType);
} }
for (Object element : source) { for (Object element : source) {
items.add(element != null ? context.convert(element, componentType) : element); items.add(element != null ? context.convert(element, componentType) : element);
} }
return getPotentiallyConvertedSimpleRead(items, targetType); return getRequiredPotentiallyConvertedSimpleRead(items, targetType);
} }
private <T> @Nullable T doConvert(Object value, Class<? extends T> target) { private <T> @Nullable T doConvert(Object value, Class<? extends T> target) {
@ -637,17 +638,17 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
* *
* @param value a value as it is returned by the driver accessing the persistence store. May be {@literal null}. * @param value a value as it is returned by the driver accessing the persistence store. May be {@literal null}.
* @param targetType {@link TypeInformation} into which the value is to be converted. Must not be {@literal null}. * @param targetType {@link TypeInformation} into which the value is to be converted. Must not be {@literal null}.
* @return The converted value. May be {@literal null}. * @return the converted value, can be {@literal null}.
*/ */
@Override @Override
@Nullable public @Nullable Object readValue(@Nullable Object value, TypeInformation<?> targetType) {
public Object readValue(@Nullable Object value, TypeInformation<?> targetType) { return null == value ? null : getPotentiallyConvertedSimpleRead(value, targetType);
}
if (null == value) {
return null;
}
return getPotentiallyConvertedSimpleRead(value, targetType); private Object getRequiredPotentiallyConvertedSimpleRead(Object value, TypeInformation<?> type) {
Object result = getPotentiallyConvertedSimpleRead(value, type);
Assert.state(result != null, "Converted must not be null");
return result;
} }
/** /**
@ -865,7 +866,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <S> S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context) { public <S> @Nullable S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context) {
Assert.notNull(source, "Source must not be null"); Assert.notNull(source, "Source must not be null");
Assert.notNull(typeHint, "TypeInformation must not be null"); Assert.notNull(typeHint, "TypeInformation must not be null");
@ -875,7 +876,6 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
} }
if (source instanceof Collection<?> collection) { if (source instanceof Collection<?> collection) {
if (typeHint.isCollectionLike() || typeHint.getType().isAssignableFrom(Collection.class)) { if (typeHint.isCollectionLike() || typeHint.getType().isAssignableFrom(Collection.class)) {
return (S) collectionConverter.convert(context, collection, typeHint); return (S) collectionConverter.convert(context, collection, typeHint);
} }
@ -1011,9 +1011,9 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
* *
* @param source must not be {@literal null}. * @param source must not be {@literal null}.
* @param typeHint must not be {@literal null}. * @param typeHint must not be {@literal null}.
* @return the converted object. * @return the converted object, can be {@literal null}.
*/ */
default <S> S convert(Object source, TypeInformation<? extends S> typeHint) { default <S> @Nullable S convert(Object source, TypeInformation<? extends S> typeHint) {
return convert(source, typeHint, this); return convert(source, typeHint, this);
} }
@ -1023,9 +1023,9 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
* @param source must not be {@literal null}. * @param source must not be {@literal null}.
* @param typeHint must not be {@literal null}. * @param typeHint must not be {@literal null}.
* @param context must not be {@literal null}. * @param context must not be {@literal null}.
* @return the converted object. * @return the converted object, can be {@literal null}.
*/ */
<S> S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context); <S> @Nullable S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context);
/** /**
* Obtain a {@link ConversionContext} for the given property {@code name}. * Obtain a {@link ConversionContext} for the given property {@code name}.
@ -1186,9 +1186,8 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
} }
@Override @Override
@Nullable
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T getPropertyValue(RelationalPersistentProperty property) { public <T> @Nullable T getPropertyValue(RelationalPersistentProperty property) {
String expression = property.getSpelExpression(); String expression = property.getSpelExpression();
Object value = expression != null ? evaluator.evaluate(expression) : accessor.get(property); Object value = expression != null ? evaluator.evaluate(expression) : accessor.get(property);
@ -1353,7 +1352,7 @@ public class MappingRelationalConverter extends AbstractRelationalConverter
} }
@Override @Override
protected <T> T potentiallyConvertExpressionValue(Object object, protected <T> @Nullable T potentiallyConvertExpressionValue(Object object,
Parameter<T, RelationalPersistentProperty> parameter) { Parameter<T, RelationalPersistentProperty> parameter) {
return context.convert(object, parameter.getType()); return context.convert(object, parameter.getType());
} }

11
spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/TypedSubtreeVisitor.java

@ -15,6 +15,7 @@
*/ */
package org.springframework.data.relational.core.sql.render; package org.springframework.data.relational.core.sql.render;
import java.util.Objects;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
@ -50,23 +51,19 @@ abstract class TypedSubtreeVisitor<T extends Visitable> extends DelegatingVisito
private final ResolvableType type; private final ResolvableType type;
private @Nullable Visitable currentSegment; private @Nullable Visitable currentSegment;
enum Assignable {
YES, NO,
}
/** /**
* Creates a new {@link TypedSubtreeVisitor}. * Creates a new {@link TypedSubtreeVisitor}.
*/ */
TypedSubtreeVisitor() { TypedSubtreeVisitor() {
this.type = refCache.computeIfAbsent(this.getClass(), this.type = Objects.requireNonNull(refCache.computeIfAbsent(this.getClass(),
key -> ResolvableType.forClass(key).as(TypedSubtreeVisitor.class).getGeneric(0)); key -> ResolvableType.forClass(key).as(TypedSubtreeVisitor.class).getGeneric(0)));
} }
/** /**
* Creates a new {@link TypedSubtreeVisitor} with an explicitly provided type. * Creates a new {@link TypedSubtreeVisitor} with an explicitly provided type.
*/ */
TypedSubtreeVisitor(Class<T> type) { TypedSubtreeVisitor(Class<T> type) {
this.type = refCache.computeIfAbsent(type, key -> ResolvableType.forClass(type)); this.type = Objects.requireNonNull(refCache.computeIfAbsent(type, key -> ResolvableType.forClass(type)));
} }
/** /**

Loading…
Cancel
Save