From 679d3d5a0809ce506c756e9a12d8d9a5896cc75a Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:43:40 +0200 Subject: [PATCH 01/15] Add `FileType` --- .../jda/api/interactions/FileType.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/main/java/net/dv8tion/jda/api/interactions/FileType.java diff --git a/src/main/java/net/dv8tion/jda/api/interactions/FileType.java b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java new file mode 100644 index 0000000000..122b738785 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java @@ -0,0 +1,100 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.interactions; + +import net.dv8tion.jda.internal.utils.Checks; +import net.dv8tion.jda.internal.utils.EntityString; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Objects; + +import javax.annotation.Nonnull; + +/** + * Represents a type of file, you can use presets such as {@link #IMAGE}, + * or specify an extension using {@link #ofExtension(String)}. + */ +public final class FileType { + /** Matches any image supported by the Discord client. */ + public static final FileType IMAGE = new FileType("image"); + /** Matches any video supported by the Discord client. */ + public static final FileType VIDEO = new FileType("video"); + /** Matches any audio supported by the Discord client. */ + public static final FileType AUDIO = new FileType("audio"); + + private final String value; + + @ApiStatus.Internal + public FileType(String value) { + this.value = value; + } + + /** + * Creates a {@link FileType} matching the provided extension. + * + * @param extension + * The extension to match against. + * + * @throws IllegalArgumentException + * + * + * @return The new {@link FileType} + */ + @Nonnull + public static FileType ofExtension(@Nonnull String extension) { + Checks.matches(extension, Checks.ALPHANUMERIC, "Extension"); + return new FileType("." + extension); + } + + /** + * The raw value of this file type. + * + * @return The raw value + */ + @Nonnull + public String getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FileType)) { + return false; + } + FileType that = (FileType) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(value); + } + + @Override + public String toString() { + return new EntityString(this) + .setName("FileType") + .addMetadata("value", value) + .toString(); + } +} From 19cf4eb95f1438a53da925a8e1d233ac30229bd7 Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Tue, 23 Jun 2026 21:03:16 +0200 Subject: [PATCH 02/15] Add `IFilterableFileTypes` Sharing with attachment uploads and slash command options --- .../interactions/IFilterableFileTypes.java | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java diff --git a/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java new file mode 100644 index 0000000000..736b7849fc --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java @@ -0,0 +1,191 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.interactions; + +import net.dv8tion.jda.internal.utils.Checks; + +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +/** + * Enables configuring a file type filter. + */ +public interface IFilterableFileTypes> { + /** The number of file type filters that can be applied at once. */ + int MAX_FILE_TYPES = 10; + + /** + * Adds up to {@value #MAX_FILE_TYPES} file types to filter for. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + T addFileTypes(@Nonnull Collection fileTypes); + + /** + * Adds up to {@value #MAX_FILE_TYPES} file types to filter for. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + default T addFileTypes(@Nonnull FileType... fileTypes) { + Checks.noneNull(fileTypes, "File types"); + return addFileTypes(Arrays.asList(fileTypes)); + } + + /** + * Adds up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

+ * + * @return This instance for chaining + */ + @Nonnull + default T addFileTypeExtensions(@Nonnull Collection extensions) { + Checks.noneNull(extensions, "Extensions"); + return addFileTypes(extensions.stream().map(FileType::ofExtension).collect(Collectors.toList())); + } + + /** + * Adds up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

    + *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • + *
  • If an extension is {@code null} or empty
  • + *
  • If an extension isn't alphanumeric
  • + *
+ * + * @return This instance for chaining + */ + @Nonnull + default T addFileTypeExtensions(@Nonnull String... extensions) { + Checks.noneNull(extensions, "Extensions"); + return addFileTypeExtensions(Arrays.asList(extensions)); + } + + /** + * Sets up to {@value #MAX_FILE_TYPES} file types to filter for. + * Pass an empty collection to remove file type filtering. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + T setFileTypes(@Nonnull Collection fileTypes); + + /** + * Sets up to {@value #MAX_FILE_TYPES} file types to filter for. + * Leave the arguments empty to remove file type filtering. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + default T setFileTypes(@Nonnull FileType... fileTypes) { + Checks.noneNull(fileTypes, "File types"); + return setFileTypes(Arrays.asList(fileTypes)); + } + + /** + * Sets up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * Pass an empty collection to remove file type filtering. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

    + *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • + *
  • If an extension is {@code null} or empty
  • + *
  • If an extension isn't alphanumeric
  • + *
+ * + * @return This instance for chaining + */ + @Nonnull + default T setFileTypeExtensions(@Nonnull Collection extensions) { + Checks.noneNull(extensions, "Extensions"); + return setFileTypes(extensions.stream().map(FileType::ofExtension).collect(Collectors.toList())); + } + + /** + * Sets up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * Leave the arguments empty to remove file type filtering. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

    + *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • + *
  • If an extension is {@code null} or empty
  • + *
  • If an extension isn't alphanumeric
  • + *
+ * + * @return This instance for chaining + */ + @Nonnull + default T setFileTypeExtensions(@Nonnull String... extensions) { + Checks.noneNull(extensions, "Extensions"); + return setFileTypeExtensions(Arrays.asList(extensions)); + } +} From c760c3a421ab76ed486c9d911e13f2c190413fba Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Fri, 26 Jun 2026 23:22:47 +0200 Subject: [PATCH 03/15] Add file type filtering to slash command options --- .../api/interactions/commands/Command.java | 20 +++++++ .../api/interactions/commands/OptionType.java | 6 ++- .../commands/build/OptionData.java | 54 ++++++++++++++++++- 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java index 61718c7c19..30a84d1c94 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java @@ -21,6 +21,7 @@ import net.dv8tion.jda.api.entities.ISnowflake; import net.dv8tion.jda.api.entities.channel.ChannelType; import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.FileType; import net.dv8tion.jda.api.interactions.IntegrationType; import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; @@ -35,6 +36,7 @@ import net.dv8tion.jda.internal.interactions.command.CommandImpl; import net.dv8tion.jda.internal.utils.Checks; import net.dv8tion.jda.internal.utils.EntityString; +import net.dv8tion.jda.internal.utils.Helpers; import net.dv8tion.jda.internal.utils.localization.LocalizationUtils; import org.jetbrains.annotations.Unmodifiable; @@ -606,6 +608,7 @@ class Option { private Number minValue; private Number maxValue; private Integer minLength, maxLength; + private final List fileTypes; public Option(@Nonnull DataObject json) { this.name = json.getString("name"); @@ -636,6 +639,10 @@ public Option(@Nonnull DataObject json) { if (!json.isNull("max_length")) { this.maxLength = json.getInt("max_length"); } + this.fileTypes = json.optArray("file_types") + .map(it -> + it.stream(DataArray::getString).map(FileType::new).collect(Helpers.toUnmodifiableList())) + .orElse(Collections.emptyList()); } /** @@ -775,6 +782,19 @@ public Integer getMaxLength() { return maxLength; } + /** + * The immutable list of file types accepted by this option. + * Returns an empty list if file types are not filtered, + * or this isn't an {@link OptionType#ATTACHMENT ATTACHMENT} option. + * + * @return Immutable list of file types accepted by this option + */ + @Nonnull + @Unmodifiable + public List getFileTypes() { + return fileTypes; + } + /** * The predefined choices available for this option. *
If no choices are defined, this returns an empty list. diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java index 911fc17240..f98a62d9f8 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java @@ -16,6 +16,7 @@ package net.dv8tion.jda.api.interactions.commands; +import net.dv8tion.jda.api.interactions.FileType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData; @@ -82,7 +83,10 @@ public enum OptionType { */ NUMBER(10, true), /** - * Options which accept a file attachment + * Options which accept a file attachment. + * + *

File types accepted by these can be filtered, such as with {@link net.dv8tion.jda.api.interactions.commands.build.OptionData#addFileTypes(FileType...) OptionData.addFileTypes(FileType...)} + * or {@link net.dv8tion.jda.api.interactions.commands.build.OptionData#setFileTypes(FileType...) OptionData.setFileTypes(FileType...)} * @see OptionMapping#getAsAttachment() */ ATTACHMENT(11), diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java index 9d8068d50c..54e10d1d70 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java @@ -19,6 +19,8 @@ import net.dv8tion.jda.api.entities.channel.ChannelType; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.FileType; +import net.dv8tion.jda.api.interactions.IFilterableFileTypes; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.localization.LocalizationMap; @@ -27,8 +29,10 @@ import net.dv8tion.jda.api.utils.data.DataType; import net.dv8tion.jda.api.utils.data.SerializableData; import net.dv8tion.jda.internal.utils.Checks; +import net.dv8tion.jda.internal.utils.Helpers; import net.dv8tion.jda.internal.utils.localization.LocalizationUtils; import org.jetbrains.annotations.Unmodifiable; +import org.jetbrains.annotations.UnmodifiableView; import java.util.*; import java.util.stream.Collectors; @@ -39,7 +43,7 @@ /** * Builder for a Slash-Command option. */ -public class OptionData implements SerializableData { +public class OptionData implements SerializableData, IFilterableFileTypes { /** * The highest positive amount Discord allows the {@link OptionType#NUMBER NUMBER} type to be. */ @@ -90,6 +94,7 @@ public class OptionData implements SerializableData { private Number maxValue; private Integer minLength, maxLength; private List choices; + private List fileTypes; /** * Create an option builder. @@ -332,6 +337,19 @@ public Integer getMaxLength() { return maxLength; } + /** + * The unmodifiable list view of file types to filter for. + * Returns an empty list if file types are not filtered, + * or this isn't an {@link OptionType#ATTACHMENT ATTACHMENT} option. + * + * @return Unmodifiable list view of file types + */ + @Nonnull + @UnmodifiableView + public List getFileTypes() { + return Collections.unmodifiableList(fileTypes); + } + /** * The choices for this option. *
This is empty by default and can only be configured for specific option types. @@ -826,6 +844,37 @@ public OptionData setRequiredLength(int minLength, int maxLength) { return this; } + @Nonnull + @Override + public OptionData addFileTypes(@Nonnull Collection fileTypes) { + Checks.noneNull(fileTypes, "File types"); + if (this.fileTypes == null) { + setFileTypes(fileTypes); + } else { + Checks.check( + this.fileTypes.size() + fileTypes.size() <= MAX_FILE_TYPES, + "Cannot have more than %d file types (provided: %d + %d)", + MAX_FILE_TYPES, + this.fileTypes.size(), + fileTypes.size()); + this.fileTypes.addAll(fileTypes); + } + return this; + } + + @Nonnull + @Override + public OptionData setFileTypes(@Nonnull Collection fileTypes) { + Checks.noneNull(fileTypes, "File types"); + Checks.check( + fileTypes.size() <= MAX_FILE_TYPES, + "Cannot have more than %d file types (provided: %d)", + MAX_FILE_TYPES, + fileTypes.size()); + this.fileTypes = Helpers.copyAsUnmodifiableList(fileTypes); + return this; + } + /** * Add a predefined choice for this option. *
The user can only provide one of the choices and cannot specify any other value. @@ -1041,6 +1090,9 @@ public DataObject toData() { json.put("max_length", maxLength); } } + if (type == OptionType.ATTACHMENT && fileTypes != null) { + json.put("file_types", fileTypes.stream().map(FileType::getValue).collect(Collectors.toList())); + } return json; } From 9e5f8222e55bfe3d2b8b9bea6a3b06f19b78b87c Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Fri, 26 Jun 2026 23:23:24 +0200 Subject: [PATCH 04/15] Add some methods to test of a file type filters for a specific media type --- .../jda/api/interactions/FileType.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/net/dv8tion/jda/api/interactions/FileType.java b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java index 122b738785..9cd65e855b 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/FileType.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java @@ -63,6 +63,33 @@ public static FileType ofExtension(@Nonnull String extension) { return new FileType("." + extension); } + /** + * Whether this file type accepts all image formats supported by Discord. + * + * @return {@code true} if this file type accepts all image formats supported by Discord, {@code false} if not + */ + public boolean isImage() { + return value.equals("image"); + } + + /** + * Whether this file type accepts all video formats supported by Discord. + * + * @return {@code true} if this file type accepts all video formats supported by Discord, {@code false} if not + */ + public boolean isVideo() { + return value.equals("video"); + } + + /** + * Whether this file type accepts all audio formats supported by Discord. + * + * @return {@code true} if this file type accepts all audio formats supported by Discord, {@code false} if not + */ + public boolean isAudio() { + return value.equals("audio"); + } + /** * The raw value of this file type. * From 78abc3532a1e5e80b4a072aa2d9a67d94997ad44 Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Fri, 26 Jun 2026 23:38:30 +0200 Subject: [PATCH 05/15] Add file type filtering for `AttachmentUpload` --- .../attachmentupload/AttachmentUpload.java | 69 ++++++++++++++++++- .../AttachmentUploadImpl.java | 28 +++++++- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java index 04cf7247d9..a7b9e1ab87 100644 --- a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java +++ b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java @@ -19,8 +19,16 @@ import net.dv8tion.jda.api.components.Component; import net.dv8tion.jda.api.components.attribute.ICustomId; import net.dv8tion.jda.api.components.label.LabelChildComponent; +import net.dv8tion.jda.api.interactions.FileType; +import net.dv8tion.jda.api.interactions.IFilterableFileTypes; import net.dv8tion.jda.internal.components.attachmentupload.AttachmentUploadImpl; import net.dv8tion.jda.internal.utils.Checks; +import net.dv8tion.jda.internal.utils.Helpers; +import org.jetbrains.annotations.UnmodifiableView; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; import javax.annotation.CheckReturnValue; import javax.annotation.Nonnull; @@ -28,7 +36,8 @@ /** * Component accepting files from users. * - *

The user can send up to {@value #MAX_UPLOADS} files, the requested number of files can be adjusted or be completely optional. + *

The user can send up to {@value #MAX_UPLOADS} files, the requested number of files can be adjusted or be completely optional, + * additionally, the accepted file types can be configured. * *

Can only be used inside {@link net.dv8tion.jda.api.components.label.Label Labels}! */ @@ -92,6 +101,16 @@ static AttachmentUpload of(@Nonnull String customId) { */ int getMaxValues(); + /** + * The unmodifiable list view of file types to filter for. + * Returns an empty list if file types are not filtered. + * + * @return Unmodifiable list view of file types + */ + @Nonnull + @UnmodifiableView + List getFileTypes(); + /** * Whether the user must send attachments. * @@ -106,11 +125,12 @@ static AttachmentUpload of(@Nonnull String customId) { /** * Builder for {@link AttachmentUpload AttachmentUploads}. */ - class Builder { + class Builder implements IFilterableFileTypes { protected int uniqueId = -1; protected String customId; protected int minValues = 1; protected int maxValues = 1; + protected List fileTypes = null; protected boolean required = true; protected Builder(@Nonnull String customId) { @@ -206,6 +226,37 @@ public Builder setRequiredRange(int min, int max) { return setMinValues(min).setMaxValues(max); } + @Nonnull + @Override + public Builder addFileTypes(@Nonnull Collection fileTypes) { + Checks.noneNull(fileTypes, "File types"); + if (this.fileTypes == null) { + setFileTypes(fileTypes); + } else { + Checks.check( + this.fileTypes.size() + fileTypes.size() <= MAX_FILE_TYPES, + "Cannot have more than %d file types (provided: %d + %d)", + MAX_FILE_TYPES, + this.fileTypes.size(), + fileTypes.size()); + this.fileTypes.addAll(fileTypes); + } + return this; + } + + @Nonnull + @Override + public Builder setFileTypes(@Nonnull Collection fileTypes) { + Checks.noneNull(fileTypes, "File types"); + Checks.check( + fileTypes.size() <= MAX_FILE_TYPES, + "Cannot have more than %d file types (provided: %d)", + MAX_FILE_TYPES, + fileTypes.size()); + this.fileTypes = Helpers.copyAsUnmodifiableList(fileTypes); + return this; + } + /** * Changes whether the user must upload files. *
Default: {@code true} @@ -264,6 +315,18 @@ public int getMaxValues() { return maxValues; } + /** + * The unmodifiable list view of file types to filter for. + * Returns an empty list if file types are not filtered. + * + * @return Unmodifiable list view of file types + */ + @Nonnull + @UnmodifiableView + public List getFileTypes() { + return Collections.unmodifiableList(fileTypes); + } + /** * Whether the user must send attachments. * @@ -288,7 +351,7 @@ public boolean isRequired() { @Nonnull public AttachmentUpload build() { Checks.check(maxValues >= minValues, "Max (%s) must be higher or equal to min (%s)", maxValues, minValues); - return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, required); + return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, fileTypes, required); } } } diff --git a/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java b/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java index 18f6334d59..18d9ccb3d7 100644 --- a/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java @@ -18,12 +18,18 @@ import net.dv8tion.jda.api.components.attachmentupload.AttachmentUpload; import net.dv8tion.jda.api.components.label.LabelChildComponentUnion; +import net.dv8tion.jda.api.interactions.FileType; +import net.dv8tion.jda.api.utils.data.DataArray; import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.internal.components.AbstractComponentImpl; import net.dv8tion.jda.internal.utils.Checks; import net.dv8tion.jda.internal.utils.EntityString; +import net.dv8tion.jda.internal.utils.Helpers; +import java.util.Collections; +import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -32,6 +38,7 @@ public class AttachmentUploadImpl extends AbstractComponentImpl implements Attac protected final String customId; protected final int minValues; protected final int maxValues; + protected final List fileTypes; protected final boolean required; public AttachmentUploadImpl(DataObject data) { @@ -40,14 +47,21 @@ public AttachmentUploadImpl(DataObject data) { data.getString("custom_id"), data.getInt("min_values", 1), data.getInt("max_values", 1), + data.optArray("file_types") + .map(it -> it.stream(DataArray::getString) + .map(FileType::new) + .collect(Helpers.toUnmodifiableList())) + .orElse(Collections.emptyList()), data.getBoolean("required", true)); } - public AttachmentUploadImpl(int uniqueId, String customId, int minValues, int maxValues, boolean required) { + public AttachmentUploadImpl( + int uniqueId, String customId, int minValues, int maxValues, List fileTypes, boolean required) { this.uniqueId = uniqueId; this.customId = customId; this.minValues = minValues; this.maxValues = maxValues; + this.fileTypes = Helpers.copyAsUnmodifiableList(fileTypes); this.required = required; } @@ -61,7 +75,7 @@ public Type getType() { @Override public AttachmentUploadImpl withUniqueId(int uniqueId) { Checks.positive(uniqueId, "Unique ID"); - return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, required); + return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, fileTypes, required); } @Override @@ -85,6 +99,12 @@ public int getMaxValues() { return maxValues; } + @Nonnull + @Override + public List getFileTypes() { + return fileTypes; + } + @Override public boolean isRequired() { return required; @@ -104,6 +124,10 @@ public DataObject toData() { json.put("id", uniqueId); } + if (fileTypes != null) { + json.put("file_types", fileTypes.stream().map(FileType::getValue).collect(Collectors.toList())); + } + return json; } From 4502e6ac390eb8df77fb242d9daeffb2e4e6d52c Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Sat, 27 Jun 2026 00:19:37 +0200 Subject: [PATCH 06/15] Add a `FileType` container to share logic between slash command options and attachment uploads --- .../attachmentupload/AttachmentUpload.java | 28 +---- .../api/interactions/commands/Command.java | 13 +- .../commands/build/OptionData.java | 31 ++--- .../AttachmentUploadImpl.java | 26 ++-- .../internal/interactions/FileTypesImpl.java | 112 ++++++++++++++++++ 5 files changed, 138 insertions(+), 72 deletions(-) create mode 100644 src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java diff --git a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java index a7b9e1ab87..d2d498cbd8 100644 --- a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java +++ b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java @@ -22,12 +22,11 @@ import net.dv8tion.jda.api.interactions.FileType; import net.dv8tion.jda.api.interactions.IFilterableFileTypes; import net.dv8tion.jda.internal.components.attachmentupload.AttachmentUploadImpl; +import net.dv8tion.jda.internal.interactions.FileTypesImpl; import net.dv8tion.jda.internal.utils.Checks; -import net.dv8tion.jda.internal.utils.Helpers; import org.jetbrains.annotations.UnmodifiableView; import java.util.Collection; -import java.util.Collections; import java.util.List; import javax.annotation.CheckReturnValue; @@ -130,7 +129,7 @@ class Builder implements IFilterableFileTypes { protected String customId; protected int minValues = 1; protected int maxValues = 1; - protected List fileTypes = null; + protected final FileTypesImpl fileTypes = FileTypesImpl.empty(); protected boolean required = true; protected Builder(@Nonnull String customId) { @@ -229,31 +228,14 @@ public Builder setRequiredRange(int min, int max) { @Nonnull @Override public Builder addFileTypes(@Nonnull Collection fileTypes) { - Checks.noneNull(fileTypes, "File types"); - if (this.fileTypes == null) { - setFileTypes(fileTypes); - } else { - Checks.check( - this.fileTypes.size() + fileTypes.size() <= MAX_FILE_TYPES, - "Cannot have more than %d file types (provided: %d + %d)", - MAX_FILE_TYPES, - this.fileTypes.size(), - fileTypes.size()); - this.fileTypes.addAll(fileTypes); - } + this.fileTypes.addAll(fileTypes); return this; } @Nonnull @Override public Builder setFileTypes(@Nonnull Collection fileTypes) { - Checks.noneNull(fileTypes, "File types"); - Checks.check( - fileTypes.size() <= MAX_FILE_TYPES, - "Cannot have more than %d file types (provided: %d)", - MAX_FILE_TYPES, - fileTypes.size()); - this.fileTypes = Helpers.copyAsUnmodifiableList(fileTypes); + this.fileTypes.setAll(fileTypes); return this; } @@ -324,7 +306,7 @@ public int getMaxValues() { @Nonnull @UnmodifiableView public List getFileTypes() { - return Collections.unmodifiableList(fileTypes); + return fileTypes.asView(); } /** diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java index 30a84d1c94..d84c7697b6 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java @@ -33,10 +33,10 @@ import net.dv8tion.jda.api.utils.data.DataArray; import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.api.utils.data.DataType; +import net.dv8tion.jda.internal.interactions.FileTypesImpl; import net.dv8tion.jda.internal.interactions.command.CommandImpl; import net.dv8tion.jda.internal.utils.Checks; import net.dv8tion.jda.internal.utils.EntityString; -import net.dv8tion.jda.internal.utils.Helpers; import net.dv8tion.jda.internal.utils.localization.LocalizationUtils; import org.jetbrains.annotations.Unmodifiable; @@ -608,7 +608,7 @@ class Option { private Number minValue; private Number maxValue; private Integer minLength, maxLength; - private final List fileTypes; + private final FileTypesImpl fileTypes; public Option(@Nonnull DataObject json) { this.name = json.getString("name"); @@ -639,10 +639,8 @@ public Option(@Nonnull DataObject json) { if (!json.isNull("max_length")) { this.maxLength = json.getInt("max_length"); } - this.fileTypes = json.optArray("file_types") - .map(it -> - it.stream(DataArray::getString).map(FileType::new).collect(Helpers.toUnmodifiableList())) - .orElse(Collections.emptyList()); + this.fileTypes = + json.optArray("file_types").map(FileTypesImpl::fromArray).orElse(FileTypesImpl.empty()); } /** @@ -792,7 +790,8 @@ public Integer getMaxLength() { @Nonnull @Unmodifiable public List getFileTypes() { - return fileTypes; + // No need for an extra copy + return fileTypes.asView(); } /** diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java index 54e10d1d70..81945213e6 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java @@ -28,8 +28,8 @@ import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.api.utils.data.DataType; import net.dv8tion.jda.api.utils.data.SerializableData; +import net.dv8tion.jda.internal.interactions.FileTypesImpl; import net.dv8tion.jda.internal.utils.Checks; -import net.dv8tion.jda.internal.utils.Helpers; import net.dv8tion.jda.internal.utils.localization.LocalizationUtils; import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.UnmodifiableView; @@ -94,7 +94,7 @@ public class OptionData implements SerializableData, IFilterableFileTypes

Remember that this only checks the extension, Discord does not check for any file signature/MIME type, + * and thus does not guarantee receiving a valid file. */ public final class FileType { /** Matches any image supported by the Discord client. */ From 1c26d109e4d923a3aa8487a322a547f027d20af4 Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Tue, 30 Jun 2026 23:14:38 +0200 Subject: [PATCH 10/15] Update extension regex This is the regex used by Discord, it allows for multiple extensions (like `tar.gz`) --- .../java/net/dv8tion/jda/api/interactions/FileType.java | 7 +++++-- .../jda/api/interactions/IFilterableFileTypes.java | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/dv8tion/jda/api/interactions/FileType.java b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java index 2693b4716f..1a687860e0 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/FileType.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.ApiStatus; import java.util.Objects; +import java.util.regex.Pattern; import javax.annotation.Nonnull; @@ -32,6 +33,8 @@ * and thus does not guarantee receiving a valid file. */ public final class FileType { + private static final Pattern EXTENSION_PATTERN = Pattern.compile("[\\w\\-.]+"); + /** Matches any image supported by the Discord client. */ public static final FileType IMAGE = new FileType("image"); /** Matches any video supported by the Discord client. */ @@ -55,14 +58,14 @@ public FileType(String value) { * @throws IllegalArgumentException *

    *
  • If the extension is {@code null} or empty
  • - *
  • If the extension isn't alphanumeric
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • *
* * @return The new {@link FileType} */ @Nonnull public static FileType ofExtension(@Nonnull String extension) { - Checks.matches(extension, Checks.ALPHANUMERIC, "Extension"); + Checks.matches(extension, EXTENSION_PATTERN, "Extension"); return new FileType("." + extension); } diff --git a/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java index 736b7849fc..05a325720e 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java @@ -74,7 +74,7 @@ default T addFileTypes(@Nonnull FileType... fileTypes) { *
    *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • *
  • If an extension is {@code null} or empty
  • - *
  • If an extension isn't alphanumeric
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • *
* * @return This instance for chaining @@ -97,7 +97,7 @@ default T addFileTypeExtensions(@Nonnull Collection extensions) { *
    *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • *
  • If an extension is {@code null} or empty
  • - *
  • If an extension isn't alphanumeric
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • *
* * @return This instance for chaining @@ -154,7 +154,7 @@ default T setFileTypes(@Nonnull FileType... fileTypes) { *
    *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • *
  • If an extension is {@code null} or empty
  • - *
  • If an extension isn't alphanumeric
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • *
* * @return This instance for chaining @@ -178,7 +178,7 @@ default T setFileTypeExtensions(@Nonnull Collection extensions) { *
    *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • *
  • If an extension is {@code null} or empty
  • - *
  • If an extension isn't alphanumeric
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • *
* * @return This instance for chaining From 3eb5355f537043a4a0993b1e94d2e61501fd8525 Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:09:50 +0200 Subject: [PATCH 11/15] "if file types are not filtered" -> "if any file is accepted" --- .../jda/api/components/attachmentupload/AttachmentUpload.java | 4 ++-- .../net/dv8tion/jda/api/interactions/commands/Command.java | 2 +- .../jda/api/interactions/commands/build/OptionData.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java index d2d498cbd8..b79739f1d0 100644 --- a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java +++ b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java @@ -102,7 +102,7 @@ static AttachmentUpload of(@Nonnull String customId) { /** * The unmodifiable list view of file types to filter for. - * Returns an empty list if file types are not filtered. + * Returns an empty list if any file is accepted. * * @return Unmodifiable list view of file types */ @@ -299,7 +299,7 @@ public int getMaxValues() { /** * The unmodifiable list view of file types to filter for. - * Returns an empty list if file types are not filtered. + * Returns an empty list if any file is accepted. * * @return Unmodifiable list view of file types */ diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java index d84c7697b6..087f5ae448 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java @@ -782,7 +782,7 @@ public Integer getMaxLength() { /** * The immutable list of file types accepted by this option. - * Returns an empty list if file types are not filtered, + * Returns an empty list if any file is accepted, * or this isn't an {@link OptionType#ATTACHMENT ATTACHMENT} option. * * @return Immutable list of file types accepted by this option diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java index e1a5fec9e0..58cea4c2e8 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java @@ -339,7 +339,7 @@ public Integer getMaxLength() { /** * The unmodifiable list view of file types to filter for. - * Returns an empty list if file types are not filtered, + * Returns an empty list if any file is accepted, * or this isn't an {@link OptionType#ATTACHMENT ATTACHMENT} option. * * @return Unmodifiable list view of file types From 3e0f2ff5ab0b3f4d777842732f8658c1711b33bb Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Sun, 2 Aug 2026 12:11:46 +0200 Subject: [PATCH 12/15] "unmodifiable list view" -> "unmodifiable list view" --- .../jda/api/components/attachmentupload/AttachmentUpload.java | 4 ++-- .../jda/api/interactions/commands/build/OptionData.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java index b79739f1d0..94626efff1 100644 --- a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java +++ b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java @@ -101,7 +101,7 @@ static AttachmentUpload of(@Nonnull String customId) { int getMaxValues(); /** - * The unmodifiable list view of file types to filter for. + * The unmodifiable list view of file types to filter for. * Returns an empty list if any file is accepted. * * @return Unmodifiable list view of file types @@ -298,7 +298,7 @@ public int getMaxValues() { } /** - * The unmodifiable list view of file types to filter for. + * The unmodifiable list view of file types to filter for. * Returns an empty list if any file is accepted. * * @return Unmodifiable list view of file types diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java index 58cea4c2e8..5fe1da0332 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java @@ -338,7 +338,7 @@ public Integer getMaxLength() { } /** - * The unmodifiable list view of file types to filter for. + * The unmodifiable list view of file types to filter for. * Returns an empty list if any file is accepted, * or this isn't an {@link OptionType#ATTACHMENT ATTACHMENT} option. * From c6427a0b612df3e114b2b8cb04ee29d5d53e4a35 Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Sun, 9 Aug 2026 22:36:17 +0200 Subject: [PATCH 13/15] Update docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Florian Spieß --- .../jda/api/interactions/IFilterableFileTypes.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java index 05a325720e..7119b9064d 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java @@ -38,7 +38,7 @@ public interface IFilterableFileTypes> { * The file types, up to {@value #MAX_FILE_TYPES} * * @throws IllegalArgumentException - * If there are more than {@value #MAX_FILE_TYPES} file types + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types * * @return This instance for chaining */ @@ -52,7 +52,7 @@ public interface IFilterableFileTypes> { * The file types, up to {@value #MAX_FILE_TYPES} * * @throws IllegalArgumentException - * If there are more than {@value #MAX_FILE_TYPES} file types + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types * * @return This instance for chaining */ @@ -116,7 +116,7 @@ default T addFileTypeExtensions(@Nonnull String... extensions) { * The file types, up to {@value #MAX_FILE_TYPES} * * @throws IllegalArgumentException - * If there are more than {@value #MAX_FILE_TYPES} file types + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types * * @return This instance for chaining */ @@ -131,7 +131,7 @@ default T addFileTypeExtensions(@Nonnull String... extensions) { * The file types, up to {@value #MAX_FILE_TYPES} * * @throws IllegalArgumentException - * If there are more than {@value #MAX_FILE_TYPES} file types + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types * * @return This instance for chaining */ From 42ba9b1f30949453e4ce16854be96d9974061951 Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Sun, 9 Aug 2026 22:48:26 +0200 Subject: [PATCH 14/15] Use empty and immutable file type list if command data doesn't have any MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Florian Spieß --- .../java/net/dv8tion/jda/api/interactions/commands/Command.java | 2 +- .../net/dv8tion/jda/internal/interactions/FileTypesImpl.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java index 087f5ae448..96139a8db7 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java @@ -640,7 +640,7 @@ public Option(@Nonnull DataObject json) { this.maxLength = json.getInt("max_length"); } this.fileTypes = - json.optArray("file_types").map(FileTypesImpl::fromArray).orElse(FileTypesImpl.empty()); + json.optArray("file_types").map(FileTypesImpl::fromArray).orElse(FileTypesImpl.EMPTY_AND_IMMUTABLE); } /** diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java index 11987b6fd4..725697f01e 100644 --- a/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java @@ -29,6 +29,8 @@ import static net.dv8tion.jda.api.interactions.IFilterableFileTypes.MAX_FILE_TYPES; public final class FileTypesImpl { + public static final FileTypesImpl EMPTY_AND_IMMUTABLE = new FileTypesImpl(Collections.emptyList()); + private final List fileTypes; private FileTypesImpl(List fileTypes) { From ab731a593f1842de9dba82d66005120cf41c275d Mon Sep 17 00:00:00 2001 From: freya02 <41875020+freya022@users.noreply.github.com> Date: Sun, 9 Aug 2026 23:00:32 +0200 Subject: [PATCH 15/15] Don't set `file_types` in `OptionData` if empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the payload smaller and avoids (third party) command cache flushes Co-authored-by: Florian Spieß --- .../jda/api/interactions/commands/build/OptionData.java | 4 +++- .../net/dv8tion/jda/internal/interactions/FileTypesImpl.java | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java index 5fe1da0332..3517d7c8c3 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java @@ -1074,7 +1074,9 @@ public DataObject toData() { } } if (type == OptionType.ATTACHMENT) { - json.put("file_types", fileTypes.toData()); + if (!fileTypes.isEmpty()) { + json.put("file_types", fileTypes.toData()); + } } return json; } diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java index 725697f01e..c491079109 100644 --- a/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java @@ -59,6 +59,10 @@ public List asView() { return Collections.unmodifiableList(fileTypes); } + public boolean isEmpty() { + return fileTypes.isEmpty(); + } + public void addAll(@Nonnull Collection fileTypes) { Checks.noneNull(fileTypes, "File types"); Checks.check(