Skip to content

Commit e5907af

Browse files
committed
jspecify nullability changes in support package
serializer and mapping packages under support. spring-projects#3762 Signed-off-by: Soby Chacko <[email protected]>
1 parent 53149d4 commit e5907af

19 files changed

+74
-52
lines changed

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/mapping/AbstractJavaTypeMapper.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2021 the original author or authors.
2+
* Copyright 2017-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import org.apache.kafka.common.header.Header;
2525
import org.apache.kafka.common.header.Headers;
2626
import org.apache.kafka.common.header.internals.RecordHeader;
27+
import org.jspecify.annotations.Nullable;
2728

2829
import org.springframework.beans.factory.BeanClassLoaderAware;
2930
import org.springframework.messaging.converter.MessageConversionException;
@@ -82,7 +83,7 @@ public abstract class AbstractJavaTypeMapper implements BeanClassLoaderAware {
8283

8384
private String keyClassIdFieldName = DEFAULT_KEY_CLASSID_FIELD_NAME;
8485

85-
private ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
86+
private @Nullable ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
8687

8788
public String getClassIdFieldName() {
8889
return this.classIdFieldName;
@@ -133,7 +134,7 @@ public void setBeanClassLoader(ClassLoader classLoader) {
133134
this.classLoader = classLoader;
134135
}
135136

136-
protected ClassLoader getClassLoader() {
137+
protected @Nullable ClassLoader getClassLoader() {
137138
return this.classLoader;
138139
}
139140

@@ -155,7 +156,7 @@ protected String retrieveHeader(Headers headers, String headerName) {
155156
return classId;
156157
}
157158

158-
protected String retrieveHeaderAsString(Headers headers, String headerName) {
159+
protected @Nullable String retrieveHeaderAsString(Headers headers, String headerName) {
159160
Header header = headers.lastHeader(headerName);
160161
if (header != null) {
161162
String classId = null;

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/mapping/ClassMapper.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2021 the original author or authors.
2+
* Copyright 2017-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.kafka.support.mapping;
1818

1919
import org.apache.kafka.common.header.Headers;
20+
import org.jspecify.annotations.Nullable;
2021

2122
/**
2223
* Strategy for setting metadata on messages such that one can create the class
@@ -32,6 +33,7 @@ public interface ClassMapper {
3233

3334
void fromClass(Class<?> clazz, Headers headers);
3435

36+
@Nullable
3537
Class<?> toClass(Headers headers);
3638

3739
}

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/mapping/DefaultJackson2JavaTypeMapper.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2024 the original author or authors.
2+
* Copyright 2017-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import com.fasterxml.jackson.databind.JavaType;
2424
import com.fasterxml.jackson.databind.type.TypeFactory;
2525
import org.apache.kafka.common.header.Headers;
26+
import org.jspecify.annotations.Nullable;
2627

2728
import org.springframework.messaging.converter.MessageConversionException;
2829
import org.springframework.util.Assert;
@@ -89,7 +90,7 @@ public void addTrustedPackages(String... packagesToTrust) {
8990
}
9091

9192
@Override
92-
public JavaType toJavaType(Headers headers) {
93+
public @Nullable JavaType toJavaType(Headers headers) {
9394
String typeIdHeader = retrieveHeaderAsString(headers, getClassIdFieldName());
9495

9596
if (typeIdHeader != null) {
@@ -181,8 +182,9 @@ public void fromClass(Class<?> clazz, Headers headers) {
181182
}
182183

183184
@Override
184-
public Class<?> toClass(Headers headers) {
185-
return toJavaType(headers).getRawClass();
185+
public @Nullable Class<?> toClass(Headers headers) {
186+
JavaType javaType = toJavaType(headers);
187+
return javaType == null ? null : javaType.getRawClass();
186188
}
187189

188190
@Override

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/mapping/Jackson2JavaTypeMapper.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2024 the original author or authors.
2+
* Copyright 2017-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import com.fasterxml.jackson.databind.JavaType;
2020
import org.apache.kafka.common.header.Headers;
21+
import org.jspecify.annotations.Nullable;
2122

2223
/**
2324
* Strategy for setting metadata on messages such that one can create the class that needs
@@ -52,6 +53,7 @@ enum TypePrecedence {
5253

5354
void fromJavaType(JavaType javaType, Headers headers);
5455

56+
@Nullable
5557
JavaType toJavaType(Headers headers);
5658

5759
TypePrecedence getTypePrecedence();
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
22
* Provides classes related to type mapping.
33
*/
4-
package org.springframework.kafka.support.mapping;
4+
@org.jspecify.annotations.NullMarked
5+
package org.springframework.kafka.support.mapping;

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/serializer/DelegatingByTopicSerialization.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public abstract class DelegatingByTopicSerialization<T extends Closeable> implem
8484

8585
private final Set<String> patterns = ConcurrentHashMap.newKeySet();
8686

87-
private T defaultDelegate;
87+
private @Nullable T defaultDelegate;
8888

8989
private boolean forKeys;
9090

@@ -93,7 +93,7 @@ public abstract class DelegatingByTopicSerialization<T extends Closeable> implem
9393
public DelegatingByTopicSerialization() {
9494
}
9595

96-
public DelegatingByTopicSerialization(Map<Pattern, T> delegates, T defaultDelegate) {
96+
public DelegatingByTopicSerialization(Map<Pattern, T> delegates, @Nullable T defaultDelegate) {
9797
Assert.notNull(delegates, "'delegates' cannot be null");
9898
Assert.notNull(defaultDelegate, "'defaultDelegate' cannot be null");
9999
this.delegates.putAll(delegates);
@@ -260,7 +260,7 @@ else if (key instanceof String regex) {
260260
}
261261
}
262262

263-
protected T instantiateAndConfigure(Map<String, ?> configs, boolean isKey, Map<Pattern, T> delegates2,
263+
protected @Nullable T instantiateAndConfigure(Map<String, ?> configs, boolean isKey, Map<Pattern, T> delegates2,
264264
@Nullable Pattern pattern, Class<?> clazz) {
265265

266266
if (pattern != null && !this.patterns.add(pattern.pattern())) {

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/serializer/DelegatingByTopicSerializer.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2022 the original author or authors.
2+
* Copyright 2019-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@ public byte[] serialize(String topic, Object data) {
7171
throw new UnsupportedOperationException();
7272
}
7373

74-
@SuppressWarnings("unchecked")
74+
@SuppressWarnings({"unchecked", "NullAway"}) // Dataflow analysis limitation
7575
@Override
7676
public byte[] serialize(String topic, Headers headers, Object data) {
7777
if (data == null) {

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/serializer/DelegatingByTypeSerializer.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2024 the original author or authors.
2+
* Copyright 2021-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -81,6 +81,7 @@ public void configure(Map<String, ?> configs, boolean isKey) {
8181
this.delegates.values().forEach(del -> del.configure(configs, isKey));
8282
}
8383

84+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
8485
@Override
8586
public byte[] serialize(String topic, Object data) {
8687
if (data == null) {
@@ -90,6 +91,7 @@ public byte[] serialize(String topic, Object data) {
9091
return delegate.serialize(topic, data);
9192
}
9293

94+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
9395
@Override
9496
public byte[] serialize(String topic, Headers headers, Object data) {
9597
if (data == null) {

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/serializer/DelegatingDeserializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ public Object deserialize(String topic, Headers headers, ByteBuffer data) {
178178
return deserializer == null ? data : deserializer.deserialize(topic, headers, data);
179179
}
180180

181-
private Deserializer<?> getDeserializerByHeaders(Headers headers) {
181+
private @Nullable Deserializer<?> getDeserializerByHeaders(Headers headers) {
182182
byte[] value = null;
183183
String selectorKey = selectorKey();
184184
Header header = headers.lastHeader(selectorKey);

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/serializer/DelegatingSerializer.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ public byte[] serialize(String topic, Object data) {
187187
throw new UnsupportedOperationException();
188188
}
189189

190+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
190191
@Override
191192
public byte[] serialize(String topic, Headers headers, Object data) {
192193
if (data == null) {
@@ -229,7 +230,7 @@ private String selectorKey() {
229230
/*
230231
* Package for testing.
231232
*/
232-
@Nullable
233+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
233234
byte[] trySerdes(Object data) {
234235
try {
235236
Serde<? extends Object> serdeFrom = Serdes.serdeFrom(data.getClass());

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/serializer/ErrorHandlingDeserializer.java

+10-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018-2023 the original author or authors.
2+
* Copyright 2018-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121

2222
import org.apache.kafka.common.header.Headers;
2323
import org.apache.kafka.common.serialization.Deserializer;
24+
import org.jspecify.annotations.Nullable;
2425

2526
import org.springframework.util.Assert;
2627
import org.springframework.util.ClassUtils;
@@ -66,13 +67,13 @@ public class ErrorHandlingDeserializer<T> implements Deserializer<T> {
6667
*/
6768
public static final String VALIDATOR_CLASS = "spring.deserializer.validator.class";
6869

69-
private Deserializer<T> delegate;
70+
private @Nullable Deserializer<T> delegate;
7071

7172
private boolean isForKey;
7273

73-
private Function<FailedDeserializationInfo, T> failedDeserializationFunction;
74+
private @Nullable Function<FailedDeserializationInfo, T> failedDeserializationFunction;
7475

75-
private Validator validator;
76+
private @Nullable Validator validator;
7677

7778
public ErrorHandlingDeserializer() {
7879
}
@@ -194,25 +195,25 @@ private void setupValidator(Map<String, ?> configs) {
194195
}
195196

196197
@Override
197-
public T deserialize(String topic, byte[] data) {
198+
public @Nullable T deserialize(String topic, byte[] data) {
198199
try {
199-
return validate(this.delegate.deserialize(topic, data));
200+
return this.delegate == null ? null : validate(this.delegate.deserialize(topic, data));
200201
}
201202
catch (Exception e) {
202203
return recoverFromSupplier(topic, null, data, e);
203204
}
204205
}
205206

206207
@Override
207-
public T deserialize(String topic, Headers headers, byte[] data) {
208+
public @Nullable T deserialize(String topic, Headers headers, byte[] data) {
208209
try {
209210
if (this.isForKey) {
210211
headers.remove(SerializationUtils.KEY_DESERIALIZER_EXCEPTION_HEADER);
211212
}
212213
else {
213214
headers.remove(SerializationUtils.VALUE_DESERIALIZER_EXCEPTION_HEADER);
214215
}
215-
return validate(this.delegate.deserialize(topic, headers, data));
216+
return this.delegate == null ? null : validate(this.delegate.deserialize(topic, headers, data));
216217
}
217218
catch (Exception e) {
218219
SerializationUtils.deserializationException(headers, data, e, this.isForKey);
@@ -228,7 +229,7 @@ private T validate(T deserialized) {
228229
return deserialized;
229230
}
230231

231-
private T recoverFromSupplier(String topic, Headers headers, byte[] data, Exception exception) {
232+
private @Nullable T recoverFromSupplier(String topic, @Nullable Headers headers, byte[] data, Exception exception) {
232233
if (this.failedDeserializationFunction != null) {
233234
FailedDeserializationInfo failedDeserializationInfo =
234235
new FailedDeserializationInfo(topic, headers, data, this.isForKey, exception);

Diff for: spring-kafka/src/main/java/org/springframework/kafka/support/serializer/FailedDeserializationInfo.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 the original author or authors.
2+
* Copyright 2019-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.util.Arrays;
2020

2121
import org.apache.kafka.common.header.Headers;
22+
import org.jspecify.annotations.Nullable;
2223

2324
/**
2425
* Class containing all the contextual information around a deserialization error.
@@ -32,7 +33,7 @@ public class FailedDeserializationInfo {
3233

3334
private final String topic;
3435

35-
private final Headers headers;
36+
private final @Nullable Headers headers;
3637

3738
private final byte[] data;
3839

@@ -48,7 +49,7 @@ public class FailedDeserializationInfo {
4849
* @param isForKey true for a key deserializer, false otherwise.
4950
* @param exception exception causing the deserialization error.
5051
*/
51-
public FailedDeserializationInfo(String topic, Headers headers, byte[] data, boolean isForKey,
52+
public FailedDeserializationInfo(String topic, @Nullable Headers headers, byte[] data, boolean isForKey,
5253
Exception exception) {
5354

5455
this.topic = topic;
@@ -62,7 +63,7 @@ public String getTopic() {
6263
return this.topic;
6364
}
6465

65-
public Headers getHeaders() {
66+
public @Nullable Headers getHeaders() {
6667
return this.headers;
6768
}
6869

0 commit comments

Comments
 (0)