Fix nullsafe FIXMEs for BlobModule.java and mark nullsafe (#50366)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/50366

Gone trough all the FIXMEs added in the previous diff by the nullsafe tool, marked the class as nullsafe and ensured no remaining violations.
Changelog: [Android][Fixed] Made BlobModule.java nullsafe

Reviewed By: cortinico

Differential Revision: D71979598

fbshipit-source-id: bbef5548d05e0b77ea03cf72f41a384fe7294d59
This commit is contained in:
Gijs Weterings
2025-04-07 06:33:09 -07:00
committed by Facebook GitHub Bot
parent 842591e480
commit c80ac8fcf2
@@ -14,6 +14,8 @@ import android.provider.MediaStore;
import android.webkit.MimeTypeMap;
import androidx.annotation.Nullable;
import com.facebook.fbreact.specs.NativeBlobModuleSpec;
import com.facebook.infer.annotation.Assertions;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
@@ -41,6 +43,7 @@ import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okio.ByteString;
@Nullsafe(Nullsafe.Mode.LOCAL)
@ReactModule(name = NativeBlobModuleSpec.NAME)
public class BlobModule extends NativeBlobModuleSpec {
@@ -106,18 +109,21 @@ public class BlobModule extends NativeBlobModuleSpec {
@Override
public RequestBody toRequestBody(ReadableMap data, String contentType) {
String type = contentType;
// NULLSAFE_FIXME[Nullable Dereference]
if (data.hasKey("type") && !data.getString("type").isEmpty()) {
if (data.hasKey("type")
&& data.getString("type") != null
&& !data.getString("type").isEmpty()) {
type = data.getString("type");
}
if (type == null) {
type = "application/octet-stream";
}
ReadableMap blob = data.getMap("blob");
// NULLSAFE_FIXME[Nullable Dereference]
String blobId = blob.getString("blobId");
// NULLSAFE_FIXME[Parameter Not Nullable, Nullable Dereference]
byte[] bytes = resolve(blobId, blob.getInt("offset"), blob.getInt("size"));
// supports() ensures blob is not null, but for nullability we have to check it
Assertions.assertNotNull(blob, "Blob is null even though supports() returned true");
byte[] bytes =
resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size"));
return RequestBody.create(MediaType.parse(type), bytes);
}
@@ -151,8 +157,7 @@ public class BlobModule extends NativeBlobModuleSpec {
}
@Override
// NULLSAFE_FIXME[Inconsistent Subclass Return Annotation]
public @Nullable Map<String, Object> getTypedExportedConstants() {
public Map<String, Object> getTypedExportedConstants() {
// The application can register BlobProvider as a ContentProvider so that blobs are resolvable.
// If it does, it needs to tell us what authority was used via this string resource.
Resources resources = getReactApplicationContext().getResources();
@@ -205,11 +210,10 @@ public class BlobModule extends NativeBlobModuleSpec {
if (sizeParam != null) {
size = Integer.parseInt(sizeParam, 10);
}
// NULLSAFE_FIXME[Parameter Not Nullable]
return resolve(blobId, offset, size);
}
public @Nullable byte[] resolve(String blobId, int offset, int size) {
public @Nullable byte[] resolve(@Nullable String blobId, int offset, int size) {
synchronized (mBlobs) {
byte[] data = mBlobs.get(blobId);
if (data == null) {
@@ -226,7 +230,6 @@ public class BlobModule extends NativeBlobModuleSpec {
}
public @Nullable byte[] resolve(ReadableMap blob) {
// NULLSAFE_FIXME[Parameter Not Nullable]
return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size"));
}
@@ -273,9 +276,8 @@ public class BlobModule extends NativeBlobModuleSpec {
}
}
private String getNameFromUri(Uri contentUri) {
private @Nullable String getNameFromUri(Uri contentUri) {
if ("file".equals(contentUri.getScheme())) {
// NULLSAFE_FIXME[Return Not Nullable]
return contentUri.getLastPathSegment();
}
String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
@@ -286,14 +288,12 @@ public class BlobModule extends NativeBlobModuleSpec {
if (metaCursor != null) {
try {
if (metaCursor.moveToFirst()) {
// NULLSAFE_FIXME[Return Not Nullable]
return metaCursor.getString(0);
}
} finally {
metaCursor.close();
}
}
// NULLSAFE_FIXME[Return Not Nullable]
return contentUri.getLastPathSegment();
}
@@ -321,15 +321,13 @@ public class BlobModule extends NativeBlobModuleSpec {
return type;
}
private WebSocketModule getWebSocketModule(String reason) {
private @Nullable WebSocketModule getWebSocketModule(String reason) {
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();
if (reactApplicationContext != null) {
// NULLSAFE_FIXME[Return Not Nullable]
return reactApplicationContext.getNativeModule(WebSocketModule.class);
}
// NULLSAFE_FIXME[Return Not Nullable]
return null;
}
@@ -340,11 +338,9 @@ public class BlobModule extends NativeBlobModuleSpec {
if (reactApplicationContext != null) {
NetworkingModule networkingModule =
reactApplicationContext.getNativeModule(NetworkingModule.class);
// NULLSAFE_FIXME[Nullable Dereference]
Assertions.assertNotNull(networkingModule, "NetworkingModule is null");
networkingModule.addUriHandler(mNetworkingUriHandler);
// NULLSAFE_FIXME[Nullable Dereference]
networkingModule.addRequestBodyHandler(mNetworkingRequestBodyHandler);
// NULLSAFE_FIXME[Nullable Dereference]
networkingModule.addResponseHandler(mNetworkingResponseHandler);
}
}
@@ -378,14 +374,10 @@ public class BlobModule extends NativeBlobModuleSpec {
WebSocketModule webSocketModule = getWebSocketModule("sendOverSocket");
if (webSocketModule != null) {
// NULLSAFE_FIXME[Parameter Not Nullable]
byte[] data = resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size"));
if (data != null) {
webSocketModule.sendBinary(ByteString.of(data), id);
} else {
// NULLSAFE_FIXME[Parameter Not Nullable]
webSocketModule.sendBinary((ByteString) null, id);
}
}
}
@@ -396,24 +388,24 @@ public class BlobModule extends NativeBlobModuleSpec {
ArrayList<byte[]> partList = new ArrayList<>(parts.size());
for (int i = 0; i < parts.size(); i++) {
ReadableMap part = parts.getMap(i);
// NULLSAFE_FIXME[Nullable Dereference]
switch (part.getString("type")) {
Assertions.assertNotNull(part, "Blob part is null");
String type = part.getString("type");
Assertions.assertNotNull(type, "Invalid type for blob: null");
switch (type) {
case "blob":
// NULLSAFE_FIXME[Nullable Dereference]
ReadableMap blob = part.getMap("data");
// NULLSAFE_FIXME[Nullable Dereference]
Assertions.assertNotNull(blob, "Blob is null");
totalBlobSize += blob.getInt("size");
// NULLSAFE_FIXME[Parameter Not Nullable]
partList.add(i, resolve(blob));
break;
case "string":
// NULLSAFE_FIXME[Nullable Dereference]
byte[] bytes = part.getString("data").getBytes(Charset.forName("UTF-8"));
String data = part.getString("data");
Assertions.assertNotNull(data, "Data is null");
byte[] bytes = data.getBytes(Charset.forName("UTF-8"));
totalBlobSize += bytes.length;
partList.add(i, bytes);
break;
default:
// NULLSAFE_FIXME[Nullable Dereference]
throw new IllegalArgumentException("Invalid type for blob: " + part.getString("type"));
}
}