diff --git a/src/main/java/net/dv8tion/jda/api/entities/Message.java b/src/main/java/net/dv8tion/jda/api/entities/Message.java
index 4415188bae..9a5cd204b0 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/Message.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/Message.java
@@ -1615,8 +1615,11 @@ default MessageAction reply(@Nonnull byte[] data, @Nonnull String name, @Nonnull
* does not have {@link net.dv8tion.jda.api.Permission#MESSAGE_MANAGE Permission.MESSAGE_MANAGE} in
* the channel.
* @throws java.lang.IllegalStateException
- * If this Message was not sent by the currently logged in account and it was not sent in a
- * {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}.
+ *
getFlags();
+ /**
+ * Returns the raw message flags of this message
+ *
+ * @throws java.lang.UnsupportedOperationException
+ * If this is a system message
+ * @return The raw message flags
+ * @see #getFlags()
+ */
+ long getFlagsRaw();
+
+ /**
+ * Whether this message is ephemeral.
+ *
The message being ephemeral means it is only visible to the bot and the interacting user
+ *
This is a shortcut method for checking if {@link #getFlags()} contains {@link MessageFlag#EPHEMERAL}
+ *
+ * @throws java.lang.UnsupportedOperationException
+ * If this is a system message
+ * @return Whether the message is ephemeral
+ */
+ boolean isEphemeral();
+
/**
* This specifies the {@link net.dv8tion.jda.api.entities.MessageType MessageType} of this Message.
*
@@ -2583,7 +2643,16 @@ enum MessageFlag
/**
* Indicates, that this Message came from the urgent message system
*/
- URGENT(4);
+ URGENT(4),
+ /**
+ * Indicates, that this Message is ephemeral, the Message is only visible to the bot and the interacting user
+ * @see Message#isEphemeral
+ */
+ EPHEMERAL(6),
+ /**
+ * Indicates, that this Message is an interaction response and the bot is "thinking"
+ */
+ LOADING(7);
private final int value;
diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/GenericComponentInteractionCreateEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/GenericComponentInteractionCreateEvent.java
index db2e5d8d38..0e6f66a449 100644
--- a/src/main/java/net/dv8tion/jda/api/events/interaction/GenericComponentInteractionCreateEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/interaction/GenericComponentInteractionCreateEvent.java
@@ -72,7 +72,7 @@ public Component getComponent()
return interaction.getComponent();
}
- @Nullable
+ @Nonnull
@Override
public Message getMessage()
{
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/ButtonInteraction.java b/src/main/java/net/dv8tion/jda/api/interactions/components/ButtonInteraction.java
index 4e626fcfc4..30914ee9c0 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/components/ButtonInteraction.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/components/ButtonInteraction.java
@@ -53,7 +53,6 @@ default Button getComponent()
/**
* Update the button with a new button instance.
- *
This only works for non-ephemeral messages where {@link #getMessage()} is available!
*
* If this interaction is already acknowledged this will use {@link #getHook()}
* and otherwise {@link #editComponents(Collection)} directly to acknowledge the interaction.
@@ -71,8 +70,6 @@ default Button getComponent()
default RestAction editButton(@Nullable Button newButton)
{
Message message = getMessage();
- if (message == null)
- throw new IllegalStateException("Cannot update button for ephemeral messages! Discord does not provide enough information to perform the update.");
List components = new ArrayList<>(message.getActionRows());
ComponentLayout.updateComponent(components, getComponentId(), newButton);
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/ComponentInteraction.java b/src/main/java/net/dv8tion/jda/api/interactions/components/ComponentInteraction.java
index d1ed44b33c..97271642f5 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/components/ComponentInteraction.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/components/ComponentInteraction.java
@@ -62,11 +62,10 @@ public interface ComponentInteraction extends Interaction
/**
* The {@link Message} instance.
- *
This is null on interactions for ephemeral messages.
*
- * @return The {@link Message}, or null if this message is ephemeral
+ * @return The {@link Message}
*/
- @Nullable
+ @Nonnull
Message getMessage();
/**
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/selections/SelectionMenuInteraction.java b/src/main/java/net/dv8tion/jda/api/interactions/components/selections/SelectionMenuInteraction.java
index 04535a8940..ab0005e9e5 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/components/selections/SelectionMenuInteraction.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/components/selections/SelectionMenuInteraction.java
@@ -85,7 +85,6 @@ default List getSelectedOptions()
/**
* Update the selection menu with a new selection menu instance.
- *
This only works for non-ephemeral messages where {@link #getMessage()} is available!
*
* If this interaction is already acknowledged this will use {@link #getHook()}
* and otherwise {@link #editComponents(Collection)} directly to acknowledge the interaction.
@@ -106,8 +105,6 @@ default List getSelectedOptions()
default RestAction editSelectionMenu(@Nullable SelectionMenu newMenu)
{
Message message = getMessage();
- if (message == null)
- throw new IllegalStateException("Cannot update selection menu for ephemeral messages! Discord does not provide enough information to perform the update.");
List components = new ArrayList<>(message.getActionRows());
ComponentLayout.updateComponent(components, getComponentId(), newMenu);
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java b/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java
index 24bab16dab..6b2d840386 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java
@@ -597,6 +597,20 @@ public EnumSet getFlags()
return null;
}
+ @Override
+ public long getFlagsRaw()
+ {
+ unsupported();
+ return 0;
+ }
+
+ @Override
+ public boolean isEphemeral()
+ {
+ unsupported();
+ return false;
+ }
+
@Nonnull
@Override
public MessageType getType()
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java b/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java
index 59df0220e1..5ddc3819bf 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java
@@ -148,6 +148,9 @@ public boolean isPinned()
@Override
public RestAction pin()
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot pin ephemeral messages.");
+
return channel.pinMessageById(getId());
}
@@ -155,6 +158,9 @@ public RestAction pin()
@Override
public RestAction unpin()
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot unpin ephemeral messages.");
+
return channel.unpinMessageById(getId());
}
@@ -162,6 +168,9 @@ public RestAction unpin()
@Override
public RestAction addReaction(@Nonnull Emote emote)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot add reactions to ephemeral messages.");
+
Checks.notNull(emote, "Emote");
boolean missingReaction = reactions.stream()
@@ -181,6 +190,9 @@ public RestAction addReaction(@Nonnull Emote emote)
@Override
public RestAction addReaction(@Nonnull String unicode)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot add reactions to ephemeral messages.");
+
return channel.addReactionById(getId(), unicode);
}
@@ -188,6 +200,8 @@ public RestAction addReaction(@Nonnull String unicode)
@Override
public RestAction clearReactions()
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot clear reactions from ephemeral messages.");
if (!isFromGuild())
throw new IllegalStateException("Cannot clear reactions from a message in a Group or PrivateChannel.");
return getTextChannel().clearReactionsById(getId());
@@ -197,6 +211,8 @@ public RestAction clearReactions()
@Override
public RestAction clearReactions(@Nonnull String unicode)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot clear reactions from ephemeral messages.");
if (!isFromGuild())
throw new IllegalStateException("Cannot clear reactions from a message in a Group or PrivateChannel.");
return getTextChannel().clearReactionsById(getId(), unicode);
@@ -206,6 +222,8 @@ public RestAction clearReactions(@Nonnull String unicode)
@Override
public RestAction clearReactions(@Nonnull Emote emote)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot clear reactions from ephemeral messages.");
if (!isFromGuild())
throw new IllegalStateException("Cannot clear reactions from a message in a Group or PrivateChannel.");
return getTextChannel().clearReactionsById(getId(), emote);
@@ -215,6 +233,9 @@ public RestAction clearReactions(@Nonnull Emote emote)
@Override
public RestAction removeReaction(@Nonnull Emote emote)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot remove reactions from ephemeral messages.");
+
return channel.removeReactionById(getId(), emote);
}
@@ -223,6 +244,8 @@ public RestAction removeReaction(@Nonnull Emote emote)
public RestAction removeReaction(@Nonnull Emote emote, @Nonnull User user)
{
Checks.notNull(user, "User"); // to prevent NPEs
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot remove reactions from ephemeral messages.");
// check if the passed user is the SelfUser, then the ChannelType doesn't matter and
// we can safely remove that
if (user.equals(getJDA().getSelfUser()))
@@ -237,6 +260,9 @@ public RestAction removeReaction(@Nonnull Emote emote, @Nonnull User user)
@Override
public RestAction removeReaction(@Nonnull String unicode)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot remove reactions from ephemeral messages.");
+
return channel.removeReactionById(getId(), unicode);
}
@@ -248,6 +274,8 @@ public RestAction removeReaction(@Nonnull String unicode, @Nonnull User us
if (user.equals(getJDA().getSelfUser()))
return channel.removeReactionById(getIdLong(), unicode);
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot remove reactions from ephemeral messages.");
if (!isFromGuild())
throw new IllegalStateException("Cannot remove reactions of others from a message in a Group or PrivateChannel.");
return getTextChannel().removeReactionById(getId(), unicode, user);
@@ -257,6 +285,9 @@ public RestAction removeReaction(@Nonnull String unicode, @Nonnull User us
@Override
public ReactionPaginationAction retrieveReactionUsers(@Nonnull Emote emote)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot retrieve reactions on ephemeral messages.");
+
return channel.retrieveReactionUsersById(id, emote);
}
@@ -264,6 +295,9 @@ public ReactionPaginationAction retrieveReactionUsers(@Nonnull Emote emote)
@Override
public ReactionPaginationAction retrieveReactionUsers(@Nonnull String unicode)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot retrieve reactions on ephemeral messages.");
+
return channel.retrieveReactionUsersById(id, unicode);
}
@@ -856,6 +890,9 @@ private void checkUser()
@Override
public AuditableRestAction delete()
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot delete ephemeral messages.");
+
if (!getJDA().getSelfUser().equals(getAuthor()))
{
if (isFromType(ChannelType.PRIVATE))
@@ -873,6 +910,9 @@ else if (!getGuild().getSelfMember()
@Override
public AuditableRestAction suppressEmbeds(boolean suppressed)
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot suppress embeds on ephemeral messages.");
+
if (!getJDA().getSelfUser().equals(getAuthor()))
{
if (isFromType(ChannelType.PRIVATE))
@@ -895,6 +935,9 @@ else if (!getGuild().getSelfMember().hasPermission(getTextChannel(), Permission.
@Override
public RestAction crosspost()
{
+ if (isEphemeral())
+ throw new IllegalStateException("Cannot crosspost ephemeral messages.");
+
if (getFlags().contains(MessageFlag.CROSSPOSTED))
return new CompletedRestAction<>(getJDA(), this);
TextChannel textChannel = getTextChannel();
@@ -918,6 +961,18 @@ public EnumSet getFlags()
return MessageFlag.fromBitField(flags);
}
+ @Override
+ public long getFlagsRaw()
+ {
+ return flags;
+ }
+
+ @Override
+ public boolean isEphemeral()
+ {
+ return (this.flags & MessageFlag.EPHEMERAL.getValue()) != 0;
+ }
+
@Override
public boolean equals(Object o)
{
diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/ComponentInteractionImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/ComponentInteractionImpl.java
index ab902c240e..456b5511a3 100644
--- a/src/main/java/net/dv8tion/jda/internal/interactions/ComponentInteractionImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/interactions/ComponentInteractionImpl.java
@@ -24,7 +24,6 @@
import net.dv8tion.jda.internal.requests.restaction.interactions.UpdateInteractionActionImpl;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
public abstract class ComponentInteractionImpl extends InteractionImpl implements ComponentInteraction
{
@@ -58,7 +57,7 @@ public String getComponentId()
return customId;
}
- @Nullable
+ @Nonnull
@Override
public Message getMessage()
{