From 8c89623a141549d2f7941bf373404a0bfc1c77c5 Mon Sep 17 00:00:00 2001 From: IoyoCode Date: Wed, 13 Sep 2023 15:12:36 +0100 Subject: [PATCH] feat(teams): implemented auto model decoding for guilds & all children --- .../com/seailz/discordjar/DiscordJar.java | 4 +- .../guild/GetCurrentUserGuildsAction.java | 3 +- .../action/sticker/ModifyStickerAction.java | 4 +- .../com/seailz/discordjar/cache/Cache.java | 34 +- .../seailz/discordjar/cache/JsonCache.java | 3 +- .../events/model/guild/GuildCreateEvent.java | 3 +- .../events/model/guild/GuildUpdateEvent.java | 3 +- .../gateway/events/DispatchedEvents.java | 7 +- .../model/application/Application.java | 7 - .../component/button/internal/ButtonImpl.java | 3 +- .../model/component/select/SelectOption.java | 3 +- .../seailz/discordjar/model/emoji/Emoji.java | 142 ++-- .../discordjar/model/emoji/Reaction.java | 3 +- .../model/emoji/sticker/Sticker.java | 186 ++--- .../model/emoji/sticker/StickerPack.java | 3 +- .../seailz/discordjar/model/guild/Guild.java | 658 ++++-------------- .../discordjar/model/guild/GuildFeature.java | 2 + .../model/guild/SystemChannelFlags.java | 29 + .../model/guild/UnavailableGuild.java | 5 +- .../guild/verification/VerificationLevel.java | 2 +- .../model/guild/welcome/WelcomeScreen.java | 38 +- .../guild/welcome/WelcomeScreenChannel.java | 58 +- .../model/interaction/data/ResolvedData.java | 2 +- .../model/invite/internal/InviteImpl.java | 2 +- .../invite/internal/InviteMetadataImpl.java | 2 +- .../discordjar/model/message/Message.java | 2 +- .../seailz/discordjar/model/role/Role.java | 176 ++--- .../seailz/discordjar/model/role/RoleTag.java | 69 +- .../model/status/activity/Activity.java | 3 +- .../seailz/discordjar/model/team/Team.java | 14 +- .../discordjar/utils/model/ModelDecoder.java | 50 +- 31 files changed, 524 insertions(+), 996 deletions(-) create mode 100644 src/main/java/com/seailz/discordjar/model/guild/SystemChannelFlags.java diff --git a/src/main/java/com/seailz/discordjar/DiscordJar.java b/src/main/java/com/seailz/discordjar/DiscordJar.java index 82a06d09..615c9b56 100644 --- a/src/main/java/com/seailz/discordjar/DiscordJar.java +++ b/src/main/java/com/seailz/discordjar/DiscordJar.java @@ -771,11 +771,11 @@ public Guild getGuildById(String id) { public Sticker getStickerById(String id) { Checker.isSnowflake(id, "Given id is not a snowflake"); try { - return Sticker.decompile(new DiscordRequest( + return (Sticker) ModelDecoder.decodeObject(new DiscordRequest( new JSONObject(), new HashMap<>(), URLS.GET.STICKER.GET_STICKER.replace("{sticker.id}", id), this, URLS.GET.STICKER.GET_STICKER, RequestMethod.GET - ).invoke().body(), this); + ).invoke().body(), Sticker.class, this); } catch (DiscordRequest.UnhandledDiscordAPIErrorException e) { if (e.getHttpCode() == 404) return null; throw new DiscordRequest.DiscordAPIErrorException(e); diff --git a/src/main/java/com/seailz/discordjar/action/guild/GetCurrentUserGuildsAction.java b/src/main/java/com/seailz/discordjar/action/guild/GetCurrentUserGuildsAction.java index 9278c672..f7fbc261 100644 --- a/src/main/java/com/seailz/discordjar/action/guild/GetCurrentUserGuildsAction.java +++ b/src/main/java/com/seailz/discordjar/action/guild/GetCurrentUserGuildsAction.java @@ -4,6 +4,7 @@ import com.seailz.discordjar.model.guild.Guild; import com.seailz.discordjar.utils.Checker; import com.seailz.discordjar.utils.URLS; +import com.seailz.discordjar.utils.model.ModelDecoder; import com.seailz.discordjar.utils.rest.DiscordRequest; import com.seailz.discordjar.utils.rest.DiscordResponse; import org.json.JSONObject; @@ -112,7 +113,7 @@ public List run() { } List returnGuilds = new ArrayList<>(); - response.arr().forEach(guild -> returnGuilds.add(Guild.decompile((JSONObject) guild, discordJar))); + response.arr().forEach(guild -> returnGuilds.add((Guild) ModelDecoder.decodeObject((JSONObject) guild, Guild.class, discordJar))); returnGuilds.forEach(g -> discordJar.getGuildCache().cache(g)); return returnGuilds; diff --git a/src/main/java/com/seailz/discordjar/action/sticker/ModifyStickerAction.java b/src/main/java/com/seailz/discordjar/action/sticker/ModifyStickerAction.java index c067f7a8..54d3d3fc 100644 --- a/src/main/java/com/seailz/discordjar/action/sticker/ModifyStickerAction.java +++ b/src/main/java/com/seailz/discordjar/action/sticker/ModifyStickerAction.java @@ -3,6 +3,7 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.model.emoji.sticker.Sticker; import com.seailz.discordjar.utils.URLS; +import com.seailz.discordjar.utils.model.ModelDecoder; import com.seailz.discordjar.utils.rest.DiscordRequest; import org.json.JSONObject; import org.springframework.web.bind.annotation.RequestMethod; @@ -54,7 +55,7 @@ public CompletableFuture run() { CompletableFuture stickerCompletableFuture = new CompletableFuture<>(); stickerCompletableFuture.completeAsync(() -> { try { - return Sticker.decompile( + return (Sticker) ModelDecoder.decodeObject( new DiscordRequest( new JSONObject() .put("name", name != null ? name : JSONObject.NULL) @@ -69,6 +70,7 @@ public CompletableFuture run() { URLS.PATCH.GUILD.STICKER.MODIFY_GUILD_STICKER, RequestMethod.PATCH ).invoke().body(), + Sticker.class, discordJar ); } catch (DiscordRequest.UnhandledDiscordAPIErrorException e) { diff --git a/src/main/java/com/seailz/discordjar/cache/Cache.java b/src/main/java/com/seailz/discordjar/cache/Cache.java index b76f125c..58b7d43d 100644 --- a/src/main/java/com/seailz/discordjar/cache/Cache.java +++ b/src/main/java/com/seailz/discordjar/cache/Cache.java @@ -3,6 +3,8 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.model.guild.Guild; import com.seailz.discordjar.model.guild.Member; +import com.seailz.discordjar.utils.model.Model; +import com.seailz.discordjar.utils.model.ModelDecoder; import com.seailz.discordjar.utils.rest.DiscordRequest; import com.seailz.discordjar.utils.rest.DiscordResponse; import org.jetbrains.annotations.NotNull; @@ -171,26 +173,32 @@ public T getById(String id) throws DiscordRequest.UnhandledDiscordAPIErrorExcept try { decompile = clazz.getMethod("decompile", JSONObject.class, DiscordJar.class, String.class, Guild.class); } catch (NoSuchMethodException exx) { - Logger.getLogger("DiscordJar").severe("Was unable to return object from cache, please report this to discord.jar's github!"); - throw new RuntimeException(exx); + decompile = null; } } } - try { + if (decompile == null) { if (response == null) return null; - returnObject.set(decompile.invoke(null, response.body(), discordJar)); - } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { + returnObject.set(ModelDecoder.decodeObject( + response.body(), (Class) clazz, discordJar + )); + } else { try { - returnObject.set(decompile.invoke(null, response.body())); - } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) { + if (response == null) return null; + returnObject.set(decompile.invoke(null, response.body(), discordJar)); + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { try { - if (guild != null) { - returnObject.set(decompile.invoke(null, response.body(), discordJar, guild.id(), guild)); - } else throw new IllegalArgumentException(ex); - } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e1) { - Logger.getLogger("DiscordJar").severe("Was unable to return object from cache, please report this to discord.jar's github!"); - return null; + returnObject.set(decompile.invoke(null, response.body())); + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) { + try { + if (guild != null) { + returnObject.set(decompile.invoke(null, response.body(), discordJar, guild.id(), guild)); + } else throw new IllegalArgumentException(ex); + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e1) { + Logger.getLogger("DiscordJar").severe("Was unable to return object from cache, please report this to discord.jar's github!"); + return null; + } } } } diff --git a/src/main/java/com/seailz/discordjar/cache/JsonCache.java b/src/main/java/com/seailz/discordjar/cache/JsonCache.java index fa6d174e..0ab28ea8 100644 --- a/src/main/java/com/seailz/discordjar/cache/JsonCache.java +++ b/src/main/java/com/seailz/discordjar/cache/JsonCache.java @@ -62,7 +62,7 @@ public interface JsonCache { * * @param interval The interval on which to invalidate the cache. */ - default void reset(int interval) { + default JsonCache reset(int interval) { new Thread(() -> { while (true) { try { @@ -73,6 +73,7 @@ default void reset(int interval) { invalidate(); } }, "djar--CacheInvalidate" + new Random().nextInt(999)).start(); + return this; } /** diff --git a/src/main/java/com/seailz/discordjar/events/model/guild/GuildCreateEvent.java b/src/main/java/com/seailz/discordjar/events/model/guild/GuildCreateEvent.java index 9a2bfa6f..f48a676d 100644 --- a/src/main/java/com/seailz/discordjar/events/model/guild/GuildCreateEvent.java +++ b/src/main/java/com/seailz/discordjar/events/model/guild/GuildCreateEvent.java @@ -3,6 +3,7 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.events.model.Event; import com.seailz.discordjar.model.guild.Guild; +import com.seailz.discordjar.utils.model.ModelDecoder; import org.jetbrains.annotations.NotNull; import org.json.JSONObject; @@ -21,6 +22,6 @@ public GuildCreateEvent(@NotNull DiscordJar bot, long sequence, @NotNull JSONObj @NotNull public Guild getGuild() { - return Guild.decompile(getJson().getJSONObject("d"), getBot()); + return (Guild) ModelDecoder.decodeObject(getJson().getJSONObject("d"), Guild.class, getBot()); } } diff --git a/src/main/java/com/seailz/discordjar/events/model/guild/GuildUpdateEvent.java b/src/main/java/com/seailz/discordjar/events/model/guild/GuildUpdateEvent.java index b272667d..ec70a144 100644 --- a/src/main/java/com/seailz/discordjar/events/model/guild/GuildUpdateEvent.java +++ b/src/main/java/com/seailz/discordjar/events/model/guild/GuildUpdateEvent.java @@ -3,6 +3,7 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.events.model.Event; import com.seailz.discordjar.model.guild.Guild; +import com.seailz.discordjar.utils.model.ModelDecoder; import org.jetbrains.annotations.NotNull; import org.json.JSONObject; @@ -13,6 +14,6 @@ public GuildUpdateEvent(@NotNull DiscordJar bot, long sequence, @NotNull JSONObj @NotNull public Guild getGuild() { - return Guild.decompile(getJson().getJSONObject("d"), getBot()); + return (Guild) ModelDecoder.decodeObject(getJson().getJSONObject("d"), Guild.class, getBot()); } } diff --git a/src/main/java/com/seailz/discordjar/gateway/events/DispatchedEvents.java b/src/main/java/com/seailz/discordjar/gateway/events/DispatchedEvents.java index bde040d3..f4893dbe 100644 --- a/src/main/java/com/seailz/discordjar/gateway/events/DispatchedEvents.java +++ b/src/main/java/com/seailz/discordjar/gateway/events/DispatchedEvents.java @@ -41,6 +41,7 @@ import com.seailz.discordjar.model.interaction.callback.InteractionCallbackType; import com.seailz.discordjar.utils.TriFunction; import com.seailz.discordjar.utils.URLS; +import com.seailz.discordjar.utils.model.ModelDecoder; import com.seailz.discordjar.utils.rest.DiscordRequest; import com.seailz.discordjar.voice.model.VoiceServerUpdate; import com.seailz.discordjar.voice.model.VoiceState; @@ -115,7 +116,7 @@ public enum DispatchedEvents { if (p.getJSONObject("d").has("unavailable") && p.getJSONObject("d").getBoolean("unavailable")) // Guild is unavailable, don't cache it return GuildCreateEvent.class; - Guild guild = Guild.decompile(p.getJSONObject("d"), g); + Guild guild = (Guild) ModelDecoder.decodeObject(p.getJSONObject("d"), Guild.class, g); g.getGuildCache().cache(guild); JSONArray arr = p.getJSONObject("d").getJSONArray("channels"); @@ -152,14 +153,14 @@ public enum DispatchedEvents { }), GUILD_UPDATE((p, g, d) -> { // modify cached guild, if it exists - Guild guild = Guild.decompile(p.getJSONObject("d"), d); + Guild guild = (Guild) ModelDecoder.decodeObject(p.getJSONObject("d"), Guild.class, d); d.getGuildCache().cache(guild); return GuildUpdateEvent.class; }), GUILD_DELETE((p, g, d) -> { // remove cached guild, if it exists - Guild guild = Guild.decompile(p.getJSONObject("d"), d); + Guild guild = (Guild) ModelDecoder.decodeObject(p.getJSONObject("d"), Guild.class, d); d.getGuildCache().remove(guild); return GuildDeleteEvent.class; diff --git a/src/main/java/com/seailz/discordjar/model/application/Application.java b/src/main/java/com/seailz/discordjar/model/application/Application.java index 39d5764f..b76469c4 100644 --- a/src/main/java/com/seailz/discordjar/model/application/Application.java +++ b/src/main/java/com/seailz/discordjar/model/application/Application.java @@ -198,13 +198,6 @@ public Application(String id, String name, String iconHash, String description, public DiscordJar discordJar() { return discordJar; } - @Override - public HashMap> customDecoders() { - return new HashMap<>(){{ - put("guild", o -> Guild.decompile(o, discordJar)); - }}; - } - private Application() {} /** diff --git a/src/main/java/com/seailz/discordjar/model/component/button/internal/ButtonImpl.java b/src/main/java/com/seailz/discordjar/model/component/button/internal/ButtonImpl.java index b9e81df8..f32effc4 100644 --- a/src/main/java/com/seailz/discordjar/model/component/button/internal/ButtonImpl.java +++ b/src/main/java/com/seailz/discordjar/model/component/button/internal/ButtonImpl.java @@ -6,6 +6,7 @@ import com.seailz.discordjar.model.component.button.Button; import com.seailz.discordjar.model.component.button.ButtonStyle; import com.seailz.discordjar.model.emoji.Emoji; +import com.seailz.discordjar.utils.model.ModelDecoder; import com.seailz.discordjar.utils.registry.components.ButtonRegistry; import org.json.JSONObject; @@ -126,7 +127,7 @@ public static Button decompile(JSONObject obj, DiscordJar discordJar) { if (obj.has("custom_id")) button.setCustomId(obj.getString("custom_id")); if (obj.has("url")) button.setUrl(obj.getString("url")); if (obj.has("disabled")) button.setDisabled(obj.getBoolean("disabled")); - if (obj.has("emoji")) button.setEmoji(Emoji.decompile(obj.getJSONObject("emoji"), discordJar)); + if (obj.has("emoji")) button.setEmoji((Emoji) ModelDecoder.decodeObject(obj.getJSONObject("emoji"), Emoji.class, discordJar)); button.setRaw(obj); return button; } diff --git a/src/main/java/com/seailz/discordjar/model/component/select/SelectOption.java b/src/main/java/com/seailz/discordjar/model/component/select/SelectOption.java index b6db2d4e..6a54cab8 100644 --- a/src/main/java/com/seailz/discordjar/model/component/select/SelectOption.java +++ b/src/main/java/com/seailz/discordjar/model/component/select/SelectOption.java @@ -3,6 +3,7 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.core.Compilerable; import com.seailz.discordjar.model.emoji.Emoji; +import com.seailz.discordjar.utils.model.ModelDecoder; import org.json.JSONObject; /** @@ -100,7 +101,7 @@ public static SelectOption decompile(JSONObject obj, DiscordJar discordJar) { option.setDescription(obj.getString("description")); } if (obj.has("emoji")) { - option.setEmoji(Emoji.decompile(obj.getJSONObject("emoji"), discordJar)); + option.setEmoji((Emoji) ModelDecoder.decodeObject(obj.getJSONObject("emoji"), Emoji.class, discordJar)); } if (obj.has("default")) { option.setDefaultSelected(obj.getBoolean("default")); diff --git a/src/main/java/com/seailz/discordjar/model/emoji/Emoji.java b/src/main/java/com/seailz/discordjar/model/emoji/Emoji.java index 9be29367..5e97e113 100644 --- a/src/main/java/com/seailz/discordjar/model/emoji/Emoji.java +++ b/src/main/java/com/seailz/discordjar/model/emoji/Emoji.java @@ -5,111 +5,79 @@ import com.seailz.discordjar.model.role.Role; import com.seailz.discordjar.model.user.User; import com.seailz.discordjar.utils.Snowflake; +import com.seailz.discordjar.utils.model.JSONProp; +import com.seailz.discordjar.utils.model.Model; import com.seailz.discordjar.utils.model.ModelDecoder; import org.json.JSONObject; import org.springframework.lang.NonNull; import java.util.ArrayList; +import java.util.List; /** * Represents a Discord Emoji - * - * @param id The emoji's ID. - * @param name The emoji's name. - * @param roles The roles that are allowed to use this emoji. - * @param user The user that created this emoji. - * @param requireColons Whether this emoji must be wrapped in colons. - * @param managed Whether this emoji is managed. - * @param animated Whether this emoji is animated. - * @param available Whether this emoji can be used, may be false due to loss of Server Boosts. */ -public record Emoji( - String id, - String name, - Role[] roles, - User user, - boolean requireColons, - boolean managed, - boolean animated, - boolean available -) implements Compilerable, Snowflake { - @Override - public JSONObject compile() { - JSONObject obj = new JSONObject(); - obj.put("id", id); - obj.put("name", name); - obj.put("roles", roles); - obj.put("user", user); - obj.put("require_colons", requireColons); - obj.put("managed", managed); - obj.put("animated", animated); - obj.put("available", available); - return obj; +public class Emoji implements Model, Snowflake { + @JSONProp("id") + private String id; + @JSONProp("name") + private String name; + @JSONProp("roles") + private List roles; + @JSONProp("user") + private User user; + @JSONProp("require_colons") + private boolean requireColons; + @JSONProp("managed") + private boolean managed; + @JSONProp("animated") + private boolean animated; + @JSONProp("available") + private boolean available; + + private Emoji() {} + + private Emoji(String id, String name, List roles, User user, boolean requireColons, boolean managed, boolean animated, boolean available) { + this.id = id; + this.name = name; + this.roles = roles; + this.user = user; + this.requireColons = requireColons; + this.managed = managed; + this.animated = animated; + this.available = available; } - @NonNull - public static Emoji decompile(JSONObject obj, DiscordJar discordJar) { - String id; - String name; - Role[] roles; - User user; - boolean requireColons; - boolean managed; - boolean animated; - boolean available; - - try { - id = obj.getString("id"); - } catch (Exception e) { - id = null; - } + public String id() { + return id; + } - try { - name = obj.getString("name"); - } catch (Exception e) { - name = null; - } + public String name() { + return name; + } - try { - ArrayList rolesList = new ArrayList<>(); - for (Object o : obj.getJSONArray("roles")) { - rolesList.add(Role.decompile((JSONObject) o)); - } - roles = rolesList.toArray(new Role[0]); - } catch (Exception e) { - roles = null; - } + public List roles() { + return roles; + } - try { - user = (User) ModelDecoder.decodeObject(obj.getJSONObject("user"), User.class, discordJar); - } catch (Exception e) { - user = null; - } + public User user() { + return user; + } - try { - requireColons = obj.getBoolean("require_colons"); - } catch (Exception e) { - requireColons = false; - } + public boolean requireColons() { + return requireColons; + } - try { - managed = obj.getBoolean("managed"); - } catch (Exception e) { - managed = false; - } + public boolean managed() { + return managed; + } - try { - animated = obj.getBoolean("animated"); - } catch (Exception e) { - animated = false; - } + public boolean animated() { + return animated; + } - try { - available = obj.getBoolean("available"); - } catch (Exception e) { - available = false; - } - return new Emoji(id, name, roles, user, requireColons, managed, animated, available); + public boolean available() { + return available; } /** diff --git a/src/main/java/com/seailz/discordjar/model/emoji/Reaction.java b/src/main/java/com/seailz/discordjar/model/emoji/Reaction.java index f08191a6..1e3dbf5d 100644 --- a/src/main/java/com/seailz/discordjar/model/emoji/Reaction.java +++ b/src/main/java/com/seailz/discordjar/model/emoji/Reaction.java @@ -2,6 +2,7 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.core.Compilerable; +import com.seailz.discordjar.utils.model.ModelDecoder; import org.json.JSONArray; import org.json.JSONObject; import org.springframework.lang.NonNull; @@ -64,7 +65,7 @@ public static Reaction decompile(JSONObject obj, DiscordJar discordJar) { } try { - emoji = Emoji.decompile(obj.getJSONObject("emoji"), discordJar); + emoji = (Emoji) ModelDecoder.decodeObject(obj.getJSONObject("emoji"), Emoji.class, discordJar); } catch (Exception e) { emoji = null; } diff --git a/src/main/java/com/seailz/discordjar/model/emoji/sticker/Sticker.java b/src/main/java/com/seailz/discordjar/model/emoji/sticker/Sticker.java index 0c0f4c1a..0b27353d 100644 --- a/src/main/java/com/seailz/discordjar/model/emoji/sticker/Sticker.java +++ b/src/main/java/com/seailz/discordjar/model/emoji/sticker/Sticker.java @@ -4,6 +4,8 @@ import com.seailz.discordjar.core.Compilerable; import com.seailz.discordjar.model.user.User; import com.seailz.discordjar.utils.Snowflake; +import com.seailz.discordjar.utils.model.JSONProp; +import com.seailz.discordjar.utils.model.Model; import com.seailz.discordjar.utils.model.ModelDecoder; import org.jetbrains.annotations.NotNull; import org.json.JSONArray; @@ -15,148 +17,82 @@ /** * Represents a sticker - * - * @param id The id of the sticker - * @param packId The id of the pack the sticker is from - * @param name The name of the sticker - * @param description The description of the sticker - * @param tags The tags for the sticker - * @param type The {@link StickerType} of the sticker - * @param format The {@link StickerFormat} of the sticker - * @param available Whether the sticker is available - * @param guildId The id of the guild that owns this sticker - * @param user The user that uploaded the guild sticker - * @param sortValue The standard sticker's sort order within its pack */ -public record Sticker( - String id, - String packId, - String name, - String description, - String tags, - StickerType type, - StickerFormat format, - boolean available, - String guildId, - User user, - int sortValue -) implements Compilerable, Snowflake { - - - /** - * Creates a {@link JSONObject} from a {@link Sticker} object - * - * @return The compiled {@link JSONObject} - */ - @Override - public JSONObject compile() { - return new JSONObject() - .put("id", id) - .put("pack_id", packId) - .put("name", name) - .put("description", description) - .put("tags", tags) - .put("type", type.getCode()) - .put("format", format.getCode()) - .put("available", available) - .put("guild_id", guildId) - .put("user", user.compile()) - .put("sort_value", sortValue); +public class Sticker implements Model, Snowflake { + + @JSONProp("id") + private String id; + @JSONProp("pack_id") + private String packId; + @JSONProp("name") + private String name; + @JSONProp("description") + private String description; + @JSONProp("tags") + private String tags; + @JSONProp("type") + private StickerType type; + @JSONProp("format_type") + private StickerFormat format; + @JSONProp("available") + private boolean available; + @JSONProp("guild_id") + private String guildId; + @JSONProp("user") + private User user; + @JSONProp("sort_value") + private int sortValue; + + private Sticker() {} + + public String id() { + return id; } - /** - * Creates a {@link Sticker} object from a {@link JSONObject} - * - * @param obj The {@link JSONObject} to create the {@link Sticker} object from - * @return The compiled {@link Sticker} object - */ - @NotNull - public static Sticker decompile(JSONObject obj, DiscordJar discordJar) { - String id; - String packId; - String name; - String description; - String tags; - StickerType type; - StickerFormat format; - boolean available; - String guildId; - User user; - int sortValue; - - try { - id = obj.getString("id"); - } catch (JSONException e) { - id = null; - } - - try { - packId = obj.getString("pack_id"); - } catch (JSONException e) { - packId = null; - } - - try { - name = obj.getString("name"); - } catch (JSONException e) { - name = null; - } + public String packId() { + return packId; + } - try { - description = obj.getString("description"); - } catch (JSONException e) { - description = null; - } + public String name() { + return name; + } - try { - tags = obj.getString("tags"); - } catch (JSONException e) { - tags = null; - } + public String description() { + return description; + } - try { - type = StickerType.getStickerTypeByCode(obj.getInt("type")); - } catch (JSONException e) { - type = null; - } + public String tags() { + return tags; + } - try { - format = StickerFormat.getStickerFormatByCode(obj.getInt("format")); - } catch (JSONException e) { - format = null; - } + public StickerType type() { + return type; + } - try { - available = obj.getBoolean("available"); - } catch (JSONException e) { - available = false; - } + public StickerFormat format() { + return format; + } - try { - guildId = obj.getString("guild_id"); - } catch (JSONException e) { - guildId = null; - } + public boolean available() { + return available; + } - try { - user = (User) ModelDecoder.decodeObject(obj.getJSONObject("user"), User.class, discordJar); - } catch (JSONException e) { - user = null; - } + public String guildId() { + return guildId; + } - try { - sortValue = obj.getInt("sort_value"); - } catch (JSONException e) { - sortValue = 0; - } + public User user() { + return user; + } - return new Sticker(id, packId, name, description, tags, type, format, available, guildId, user, sortValue); + public int sortValue() { + return sortValue; } public static List decompileList(JSONArray array, DiscordJar discordJar) { List stickers = new ArrayList<>(); for (int i = 0; i < array.length(); i++) { - stickers.add(decompile(array.getJSONObject(i), discordJar)); + stickers.add((Sticker) ModelDecoder.decodeObject(array.getJSONObject(i), Sticker.class, discordJar)); } return stickers; } diff --git a/src/main/java/com/seailz/discordjar/model/emoji/sticker/StickerPack.java b/src/main/java/com/seailz/discordjar/model/emoji/sticker/StickerPack.java index 00345971..e781242d 100644 --- a/src/main/java/com/seailz/discordjar/model/emoji/sticker/StickerPack.java +++ b/src/main/java/com/seailz/discordjar/model/emoji/sticker/StickerPack.java @@ -3,6 +3,7 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.core.Compilerable; import com.seailz.discordjar.utils.Snowflake; +import com.seailz.discordjar.utils.model.ModelDecoder; import org.json.JSONArray; import org.json.JSONObject; @@ -37,7 +38,7 @@ public JSONObject compile() { public static StickerPack decompile(JSONObject json, DiscordJar discordJar) { List stickers = new ArrayList<>(); - json.getJSONArray("stickers").forEach(object -> stickers.add(Sticker.decompile((JSONObject) object, discordJar))); + json.getJSONArray("stickers").forEach(object -> stickers.add((Sticker) ModelDecoder.decodeObject((JSONObject) object, Sticker.class, discordJar))); return new StickerPack( json.getString("id"), diff --git a/src/main/java/com/seailz/discordjar/model/guild/Guild.java b/src/main/java/com/seailz/discordjar/model/guild/Guild.java index 484f5038..7abad671 100644 --- a/src/main/java/com/seailz/discordjar/model/guild/Guild.java +++ b/src/main/java/com/seailz/discordjar/model/guild/Guild.java @@ -31,6 +31,9 @@ import com.seailz.discordjar.model.role.Role; import com.seailz.discordjar.model.user.User; import com.seailz.discordjar.utils.*; +import com.seailz.discordjar.utils.model.DiscordJarProp; +import com.seailz.discordjar.utils.model.JSONProp; +import com.seailz.discordjar.utils.model.Model; import com.seailz.discordjar.utils.model.ModelDecoder; import com.seailz.discordjar.utils.rest.DiscordRequest; import com.seailz.discordjar.utils.rest.DiscordResponse; @@ -49,147 +52,124 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; import java.util.logging.Logger; import java.util.stream.Collectors; /** * Represents a guild. */ -public class Guild implements Compilerable, Snowflake, CDNAble { - private final String id; - private final String name; - private final String icon; - private final String iconHash; - private final String splash; - private final String discoverySplash; - private final boolean isOwner; - private final User owner; - private final String permissions; - private final Channel afkChannel; - private final int afkTimeout; - private final boolean isWidgetEnabled; +public class Guild implements Model, Snowflake, CDNAble { + @JSONProp("id") + private String id; + @JSONProp("name") + private String name; + @JSONProp("icon") + private String icon; + @JSONProp("icon_hash") + private String iconHash; + @JSONProp("splash") + private String splash; + @JSONProp("discovery_splash") + private String discoverySplash; + @JSONProp("owner") + private boolean isOwner; + @JSONProp("owner_id") + private String ownerId; + private User owner; + @JSONProp("permissions") + private String permissions; + @JSONProp("region") + private String region; + @JSONProp("afk_channel_id") + private String afkChannelId; + private Channel afkChannel; + @JSONProp("afk_timeout") + private int afkTimeout; + @JSONProp("widget_enabled") + private boolean isWidgetEnabled; private Channel widgetChannel = null; - private final String widgetChannelId; - private final VerificationLevel verificationLevel; - private final DefaultMessageNotificationLevel defaultMessageNotificationLevel; - private final ExplicitContentFilterLevel explicitContentFilterLevel; - private final List roles; - private final List emojis; - private final EnumSet features; - private final MFALevel mfaLevel; - private final String applicationId; + @JSONProp("widget_channel_id") + private String widgetChannelId; + @JSONProp("verification_level") + private VerificationLevel verificationLevel; + @JSONProp("default_message_notifications") + private DefaultMessageNotificationLevel defaultMessageNotificationLevel; + @JSONProp("explicit_content_filter") + private ExplicitContentFilterLevel explicitContentFilterLevel; + @JSONProp("roles") + private List roles; + @JSONProp("emojis") + private List emojis; + @JSONProp("features") + private EnumSet features; + @JSONProp("mfa_level") + private MFALevel mfaLevel; + @JSONProp("application_id") + private String applicationId; private Channel systemChannel; - private final String systemChannelId; - private final int maxPresences; - private final int maxMembers; - private final String vanityUrlCode; - private final String description; - private final String banner; - private final PremiumTier premiumTier; - private final int premiumSubscriptionCount; - private final String preferredLocale; + @JSONProp("system_channel_id") + private String systemChannelId; + @JSONProp("system_channel_flags") + private SystemChannelFlags systemChannelFlags; + @JSONProp("rules_channel_id") + private String rulesChannelId; + private Channel rulesChannel = null; + @JSONProp("max_presences") + private int maxPresences; + @JSONProp("max_members") + private int maxMembers; + @JSONProp("vanity_url_code") + private String vanityUrlCode; + @JSONProp("description") + private String description; + @JSONProp("banner") + private String banner; + @JSONProp("premium_tier") + private PremiumTier premiumTier; + @JSONProp("premium_subscription_count") + private int premiumSubscriptionCount; + @JSONProp("preferred_locale") + private String preferredLocale; private Channel publicUpdatesChannel; - private final String publicUpdatesChannelId; - private final int maxVideoChannelUsers; - private final int maxStageVideoChannelUsers; - private final int approximateMemberCount; - private final int approximatePresenceCount; - private final WelcomeScreen welcomeScreen; - private final List stickers; - private final boolean premiumProgressBarEnabled; - private final String safetyAlertChannelId; + @JSONProp("public_updates_channel_id") + private String publicUpdatesChannelId; + @JSONProp("max_video_channel_users") + private int maxVideoChannelUsers; + @JSONProp("max_stage_video_channel_users") + private int maxStageVideoChannelUsers; + @JSONProp("approximate_member_count") + private int approximateMemberCount; + @JSONProp("approximate_presence_count") + private int approximatePresenceCount; + @JSONProp("welcome_screen") + private WelcomeScreen welcomeScreen; + @JSONProp("stickers") + private List stickers; + @JSONProp("premium_progress_bar_enabled") + private boolean premiumProgressBarEnabled; + @JSONProp("safety_alerts_channel_id") + private String safetyAlertChannelId; private Channel safetyAlertChannel = null; - private final DiscordJar discordJar; - private final JsonCache roleCache; - - public Guild( - String id, - String name, - String icon, - String iconHash, - String splash, - String discoverySplash, - boolean isOwner, - User owner, - String permissions, - Channel afkChannel, - int afkTimeout, - boolean isWidgetEnabled, - String widgetChannelId, - VerificationLevel verificationLevel, - DefaultMessageNotificationLevel defaultMessageNotificationLevel, - ExplicitContentFilterLevel explicitContentFilterLevel, - List roles, - List emojis, - EnumSet features, - MFALevel mfaLevel, - String applicationId, - Channel systemChannel, - String systemChannelId, - int maxPresences, - int maxMembers, - String vanityUrlCode, - String description, - String banner, - PremiumTier premiumTier, - int premiumSubscriptionCount, - String preferredLocale, - Channel publicUpdatesChannel, - String publicUpdatesChannelId, - int maxVideoChannelUsers, - int maxStageVideoChannelUsers, - int approximateMemberCount, - int approximatePresenceCount, - WelcomeScreen welcomeScreen, - List stickers, - boolean premiumProgressBarEnabled, - String safetyAlertChannelId, - DiscordJar discordJar, - JsonCache roleCache - ) { - this.id = id; - this.name = name; - this.icon = icon; - this.iconHash = iconHash; - this.splash = splash; - this.discoverySplash = discoverySplash; - this.isOwner = isOwner; - this.owner = owner; - this.permissions = permissions; - this.afkChannel = afkChannel; - this.afkTimeout = afkTimeout; - this.isWidgetEnabled = isWidgetEnabled; - this.widgetChannelId = widgetChannelId; - this.verificationLevel = verificationLevel; - this.defaultMessageNotificationLevel = defaultMessageNotificationLevel; - this.explicitContentFilterLevel = explicitContentFilterLevel; - this.roles = roles; - this.emojis = emojis; - this.features = features; - this.mfaLevel = mfaLevel; - this.applicationId = applicationId; - this.systemChannel = systemChannel; - this.systemChannelId = systemChannelId; - this.maxPresences = maxPresences; - this.maxMembers = maxMembers; - this.vanityUrlCode = vanityUrlCode; - this.description = description; - this.banner = banner; - this.premiumTier = premiumTier; - this.premiumSubscriptionCount = premiumSubscriptionCount; - this.preferredLocale = preferredLocale; - this.publicUpdatesChannel = publicUpdatesChannel; - this.publicUpdatesChannelId = publicUpdatesChannelId; - this.maxVideoChannelUsers = maxVideoChannelUsers; - this.maxStageVideoChannelUsers = maxStageVideoChannelUsers; - this.approximateMemberCount = approximateMemberCount; - this.approximatePresenceCount = approximatePresenceCount; - this.welcomeScreen = welcomeScreen; - this.stickers = stickers; - this.premiumProgressBarEnabled = premiumProgressBarEnabled; - this.safetyAlertChannelId = safetyAlertChannelId; - this.discordJar = discordJar; - this.roleCache = roleCache; + @DiscordJarProp + private DiscordJar discordJar; + @JSONProp("role_cache_priv_obj") + private JsonCache roleCache; + + private Guild() {} + + @Override + public HashMap> customDecoders() { + return new HashMap<>(){{ + put("role_cache_priv_obj", (j) -> JsonCache.newc(new DiscordRequest( + new JSONObject(), + new HashMap<>(), + URLS.GET.GUILDS.ROLES.GET_GUILD_ROLES.replace("{guild.id}", id), + discordJar, + URLS.GET.GUILDS.ROLES.GET_GUILD_ROLES, + RequestMethod.GET + )).reset(60000)); + }}; } public String id() { @@ -216,11 +196,16 @@ public String discoverySplash() { return discoverySplash; } + public String regionId() { + return region; + } + public boolean isOwner() { return isOwner; } public User owner() { + if (owner == null) owner = discordJar.getUserById(ownerId); return owner; } @@ -229,6 +214,7 @@ public String permissions() { } public Channel afkChannel() { + if (afkChannel == null) afkChannel = discordJar.getChannelById(afkChannelId); return afkChannel; } @@ -251,6 +237,14 @@ public DefaultMessageNotificationLevel defaultMessageNotificationLevel() { public ExplicitContentFilterLevel explicitContentFilterLevel() { return explicitContentFilterLevel; } + public SystemChannelFlags systemChannelFlags() { + return systemChannelFlags; + } + + public Channel rulesChannel() { + if (rulesChannel == null) rulesChannel = discordJar.getChannelById(rulesChannelId); + return rulesChannel; + } public List emojis() { return emojis; @@ -340,394 +334,6 @@ public JsonCache roleCache() { return roleCache; } - - @Override - public JSONObject compile() { - return new JSONObject() - .put("id", id) - .put("name", name) - .put("icon", icon) - .put("icon_hash", iconHash) - .put("splash", splash) - .put("discovery_splash", discoverySplash) - .put("owner", isOwner) - .put("owner_id", owner) - .put("permissions", permissions) - .put("afk_channel_id", afkChannel.id()) - .put("afk_timeout", afkTimeout) - .put("widget_enabled", isWidgetEnabled) - .put("widget_channel_id", widgetChannel.id()) - .put("verification_level", verificationLevel.getCode()) - .put("default_message_notifications", defaultMessageNotificationLevel.getCode()) - .put("explicit_content_filter", explicitContentFilterLevel.getCode()) - .put("roles", roles) - .put("emojis", emojis) - .put("features", features) - .put("mfa_level", mfaLevel.getCode()) - .put("application_id", applicationId) - .put("system_channel_id", systemChannelId) - .put("max_presences", maxPresences) - .put("max_members", maxMembers) - .put("vanity_url_code", vanityUrlCode) - .put("description", description) - .put("banner", banner) - .put("premium_tier", premiumTier.getCode()) - .put("premium_subscription_count", premiumSubscriptionCount) - .put("preferred_locale", preferredLocale) - .put("public_updates_channel_id", publicUpdatesChannelId) - .put("max_video_channel_users", maxVideoChannelUsers) - .put("max_stage_video_channel_users", maxStageVideoChannelUsers) - .put("approximate_member_count", approximateMemberCount) - .put("approximate_presence_count", approximatePresenceCount) - .put("welcome_screen", welcomeScreen) - .put("stickers", stickers) - .put("premium_progress_bar_enabled", premiumProgressBarEnabled) - .put("safety_alerts_channel_id", safetyAlertChannelId); - } - - @NotNull - public static Guild decompile(JSONObject obj, DiscordJar discordJar) { - long nano = System.nanoTime(); - String id; - String name; - String icon; - String iconHash; - String splash; - String discoverySplash; - boolean isOwner; - User owner; - String permissions; - Channel afkChannel; - int afkTimeout; - boolean isWidgetEnabled; - String widgetChannelId; - VerificationLevel verificationLevel; - DefaultMessageNotificationLevel defaultMessageNotificationLevel; - ExplicitContentFilterLevel explicitContentFilterLevel; - List roles; - List emojis; - EnumSet features; - MFALevel mfaLevel; - String applicationId; - String systemChannelId; - int maxPresences; - int maxMembers; - String vanityUrlCode; - String description; - String banner; - PremiumTier premiumTier; - int premiumSubscriptionCount; - String preferredLocale; - String publicUpdatesChannelId; - int maxVideoChannelUsers; - int maxStageVideoChannelUsers = 0; - int approximateMemberCount; - int approximatePresenceCount; - WelcomeScreen welcomeScreen; - List stickers; - boolean premiumProgressBarEnabled; - String safetyAlertsChannelId = null; - - try { - id = obj.getString("id"); - } catch (JSONException e) { - id = null; - } - - try { - name = obj.getString("name"); - } catch (JSONException e) { - name = null; - } - - try { - icon = obj.getString("icon"); - } catch (JSONException e) { - icon = null; - } - - try { - iconHash = obj.getString("icon_hash"); - } catch (JSONException e) { - iconHash = null; - } - - try { - splash = obj.getString("splash"); - } catch (JSONException e) { - splash = null; - } - - try { - discoverySplash = obj.getString("discovery_splash"); - } catch (JSONException e) { - discoverySplash = null; - } - - try { - isOwner = obj.getBoolean("owner"); - } catch (JSONException e) { - isOwner = false; - } - - try { - owner = (User) ModelDecoder.decodeObject(obj.getJSONObject("owner"), User.class, discordJar); - } catch (JSONException e) { - owner = null; - } - - try { - permissions = obj.getString("permissions"); - } catch (JSONException e) { - permissions = null; - } - - try { - afkChannel = Channel.decompile(obj.getJSONObject("afk_channel"), discordJar); - } catch (JSONException e) { - afkChannel = null; - } - - try { - afkTimeout = obj.getInt("afk_timeout"); - } catch (JSONException e) { - afkTimeout = 0; - } - - try { - isWidgetEnabled = obj.getBoolean("widget_enabled"); - } catch (JSONException e) { - isWidgetEnabled = false; - } - - try { - widgetChannelId =obj.getString("widget_channel_id"); - } catch (JSONException e) { - widgetChannelId = null; - } - - try { - verificationLevel = VerificationLevel.getVerificationLevel(obj.getInt("verification_level")); - } catch (JSONException e) { - verificationLevel = null; - } - - try { - defaultMessageNotificationLevel = DefaultMessageNotificationLevel.getDefaultMessageNotificationLevel(obj.getInt("default_message_notifications")); - } catch (JSONException e) { - defaultMessageNotificationLevel = null; - } - - try { - explicitContentFilterLevel = ExplicitContentFilterLevel.getExplicitContentFilterLevel(obj.getInt("explicit_content_filter")); - } catch (JSONException e) { - explicitContentFilterLevel = null; - } - - try { - JSONArray rolesArray = obj.getJSONArray("roles"); - roles = new ArrayList<>(); - for (int i = 0; i < rolesArray.length(); i++) { - roles.add(Role.decompile(rolesArray.getJSONObject(i))); - } - } catch (JSONException e) { - roles = null; - } - - try { - JSONArray emojisArray = obj.getJSONArray("emojis"); - emojis = new ArrayList<>(); - for (int i = 0; i < emojisArray.length(); i++) { - emojis.add(Emoji.decompile(emojisArray.getJSONObject(i), discordJar)); - } - } catch (JSONException e) { - emojis = null; - } - - try { - features = GuildFeature.getGuildFeatures(obj.getJSONArray("features").toList().toArray(new String[0])); - } catch (JSONException e) { - features = null; - } - - try { - mfaLevel = MFALevel.getMFALevel(obj.getInt("mfa_level")); - } catch (JSONException e) { - mfaLevel = null; - } - - try { - applicationId = obj.getString("application_id"); - } catch (JSONException e) { - applicationId = null; - } - - try { - systemChannelId = obj.getString("system_channel_id"); - } catch (IllegalArgumentException | JSONException e) { - systemChannelId = null; - } - - try { - maxPresences = obj.getInt("max_presences"); - } catch (JSONException e) { - maxPresences = 0; - } - - try { - maxMembers = obj.getInt("max_members"); - } catch (JSONException e) { - maxMembers = 0; - } - - try { - vanityUrlCode = obj.getString("vanity_url_code"); - } catch (JSONException e) { - vanityUrlCode = null; - } - - try { - description = obj.getString("description"); - } catch (JSONException e) { - description = null; - } - - try { - banner = obj.getString("banner"); - } catch (JSONException e) { - banner = null; - } - - try { - premiumTier = PremiumTier.getPremiumTier(obj.getInt("premium_tier")); - } catch (JSONException e) { - premiumTier = null; - } - - try { - premiumSubscriptionCount = obj.getInt("premium_subscription_count"); - } catch (JSONException e) { - premiumSubscriptionCount = 0; - } - - try { - preferredLocale = obj.getString("preferred_locale"); - } catch (JSONException e) { - preferredLocale = null; - } - - try { - publicUpdatesChannelId = obj.getString("public_updates_channel_id"); - } catch (Exception e) { - publicUpdatesChannelId = null; - } - - try { - maxVideoChannelUsers = obj.getInt("max_video_channel_users"); - } catch (JSONException e) { - maxVideoChannelUsers = 0; - } - - try { - approximateMemberCount = obj.getInt("approximate_member_count"); - } catch (JSONException e) { - approximateMemberCount = 0; - } - - try { - approximateMemberCount = obj.getInt("approximate_member_count"); - } catch (JSONException e) { - approximateMemberCount = 0; - } - - try { - approximatePresenceCount = obj.getInt("approximate_presence_count"); - } catch (JSONException e) { - approximatePresenceCount = 0; - } - - try { - welcomeScreen = WelcomeScreen.decompile(obj.getJSONObject("welcome_screen"), discordJar); - } catch (JSONException e) { - welcomeScreen = null; - } - - try { - JSONArray stickersArray = obj.getJSONArray("stickers"); - stickers = new ArrayList<>(); - for (int i = 0; i < stickersArray.length(); i++) { - stickers.add(Sticker.decompile(stickersArray.getJSONObject(i), discordJar)); - } - } catch (JSONException e) { - stickers = null; - } - - try { - premiumProgressBarEnabled = obj.getBoolean("premium_progress_bar_enabled"); - } catch (JSONException e) { - premiumProgressBarEnabled = false; - } - - if (obj.has("safety_alerts_channel_id") && !obj.isNull("safety_alerts_channel_id")) { - safetyAlertsChannelId = obj.getString("safety_alerts_channel_id"); - } - - Guild g = new Guild( - id, - name, - icon, - iconHash, - splash, - discoverySplash, - isOwner, - owner, - permissions, - afkChannel, - afkTimeout, - isWidgetEnabled, - widgetChannelId, - verificationLevel, - defaultMessageNotificationLevel, - explicitContentFilterLevel, - roles, - emojis, - features, - mfaLevel, - applicationId, - null, - systemChannelId, - maxPresences, - maxMembers, - vanityUrlCode, - description, - banner, - premiumTier, - premiumSubscriptionCount, - preferredLocale, - null, - publicUpdatesChannelId, - maxVideoChannelUsers, - maxStageVideoChannelUsers, - approximateMemberCount, - approximatePresenceCount, - welcomeScreen, - stickers, - premiumProgressBarEnabled, - safetyAlertsChannelId, - discordJar, - JsonCache.newc(new DiscordRequest( - new JSONObject(), - new HashMap<>(), - URLS.GET.GUILDS.ROLES.GET_GUILD_ROLES.replace("{guild.id}", id), - discordJar, - URLS.GET.GUILDS.ROLES.GET_GUILD_ROLES, - RequestMethod.GET - )) - ); - g.roleCache.reset(60000); - return g; - } - public Channel systemChannel() { if (systemChannelId == null) return null; if (this.systemChannel != null) return this.systemChannel; @@ -808,7 +414,7 @@ public List getStickers() { */ public Sticker getStickerById(String stickerId) { try { - return Sticker.decompile( + return (Sticker) ModelDecoder.decodeObject( new DiscordRequest( new JSONObject(), new HashMap<>(), @@ -823,6 +429,7 @@ public Sticker getStickerById(String stickerId) { URLS.GET.GUILDS.STICKERS.GET_GUILD_STICKER, RequestMethod.GET ).invoke().body(), + Sticker.class, discordJar ); } catch (DiscordRequest.UnhandledDiscordAPIErrorException e) { @@ -1020,7 +627,7 @@ public List getEmojis() { discordJar, URLS.GET.GUILDS.EMOJIS.GUILD_EMOJIS, RequestMethod.GET - ).invoke().arr().forEach((object) -> emojis.add(Emoji.decompile((JSONObject) object, discordJar))); + ).invoke().arr().forEach((object) -> emojis.add((Emoji) ModelDecoder.decodeObject((JSONObject) object, Emoji.class, discordJar))); } catch (DiscordRequest.UnhandledDiscordAPIErrorException e) { throw new DiscordRequest.DiscordAPIErrorException(e); } @@ -1035,7 +642,7 @@ public List getEmojis() { */ public Emoji getEmojiById(@NotNull String emojiId) { try { - return Emoji.decompile( + return (Emoji) ModelDecoder.decodeObject( new DiscordRequest( new JSONObject(), new HashMap<>(), @@ -1044,6 +651,7 @@ public Emoji getEmojiById(@NotNull String emojiId) { URLS.GET.GUILDS.GET_GUILD, RequestMethod.GET ).invoke().body(), + Emoji.class, discordJar ); } catch (DiscordRequest.UnhandledDiscordAPIErrorException e) { @@ -1101,7 +709,7 @@ public List roles() { if (roleCache != null && !roleCache.isEmpty()) { List roles = new ArrayList<>(); roleCache.get().getJSONArray("data").forEach( - o -> roles.add(Role.decompile((JSONObject) o)) + o -> roles.add((Role) ModelDecoder.decodeObject((JSONObject) o, Role.class, discordJar)) ); return roles; } @@ -1127,7 +735,7 @@ public List roles() { System.out.println(response.code() + " " + (response.body() == null ? "null" : response.body().toString())); } - res.forEach(o -> roles.add(Role.decompile((JSONObject) o))); + res.forEach(o -> roles.add((Role) ModelDecoder.decodeObject((JSONObject) o, Role.class, discordJar))); if (roleCache != null) { roleCache.update(new JSONObject().put("data", res)); @@ -1989,7 +1597,7 @@ public static Option decompile(@NotNull JSONObject obj, DiscordJar discordJar) { obj.has("id") ? obj.getString("id") : null, obj.getJSONArray("channel_ids").toList().stream().map(o -> (String) o).collect(Collectors.toList()), obj.getJSONArray("role_ids").toList().stream().map(o -> (String) o).collect(Collectors.toList()), - Emoji.decompile(obj.getJSONObject("emoji"), discordJar), + (Emoji) ModelDecoder.decodeObject(obj.getJSONObject("emoji"), Emoji.class, discordJar), obj.getString("title"), obj.getString("description") ); diff --git a/src/main/java/com/seailz/discordjar/model/guild/GuildFeature.java b/src/main/java/com/seailz/discordjar/model/guild/GuildFeature.java index 1d952ec7..80240afd 100644 --- a/src/main/java/com/seailz/discordjar/model/guild/GuildFeature.java +++ b/src/main/java/com/seailz/discordjar/model/guild/GuildFeature.java @@ -67,7 +67,9 @@ public enum GuildFeature { public static EnumSet getGuildFeatures(String[] features) { EnumSet guildFeatures = EnumSet.noneOf(GuildFeature.class); + if (features == null) return guildFeatures; for (String feature : features) { + if (feature == null) continue; try { guildFeatures.add(GuildFeature.valueOf(feature.toUpperCase())); } catch (IllegalArgumentException e) { diff --git a/src/main/java/com/seailz/discordjar/model/guild/SystemChannelFlags.java b/src/main/java/com/seailz/discordjar/model/guild/SystemChannelFlags.java new file mode 100644 index 00000000..89a1e25a --- /dev/null +++ b/src/main/java/com/seailz/discordjar/model/guild/SystemChannelFlags.java @@ -0,0 +1,29 @@ +package com.seailz.discordjar.model.guild; + +import com.seailz.discordjar.utils.flag.Bitwiseable; + +public enum SystemChannelFlags implements Bitwiseable { + SUPPRESS_JOIN_NOTIFICATIONS(0), + SUPPRESS_PREMIUM_SUBSCRIPTIONS(1), + SUPPRESS_GUILD_REMINDER_NOTIFICATIONS(2), + SUPPRESS_JOIN_NOTIFICATION_REPLIES(3), + SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATIONS(4), + SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATION_REPLIES(5) + ; + + private final int id; + + SystemChannelFlags(int id) { + this.id = id; + } + + @Override + public int getLeftShiftId() { + return 1 << id; + } + + @Override + public int id() { + return id; + } +} diff --git a/src/main/java/com/seailz/discordjar/model/guild/UnavailableGuild.java b/src/main/java/com/seailz/discordjar/model/guild/UnavailableGuild.java index cc6b3426..dac4528d 100644 --- a/src/main/java/com/seailz/discordjar/model/guild/UnavailableGuild.java +++ b/src/main/java/com/seailz/discordjar/model/guild/UnavailableGuild.java @@ -5,6 +5,7 @@ import com.seailz.discordjar.model.emoji.Emoji; import com.seailz.discordjar.model.emoji.sticker.Sticker; import com.seailz.discordjar.utils.Snowflake; +import com.seailz.discordjar.utils.model.ModelDecoder; import org.jetbrains.annotations.NotNull; import org.json.JSONArray; import org.json.JSONException; @@ -115,7 +116,7 @@ public static UnavailableGuild decompile(JSONObject obj, DiscordJar discordjv) { JSONArray emojiArray = obj.getJSONArray("emojis"); for (int i = 0; i < emojiArray.length(); i++) { - emojiList.add(Emoji.decompile(emojiArray.getJSONObject(i), discordjv)); + emojiList.add((Emoji) ModelDecoder.decodeObject(emojiArray.getJSONObject(i), Emoji.class, discordjv)); } emojis = emojiList; } catch (JSONException e) { @@ -157,7 +158,7 @@ public static UnavailableGuild decompile(JSONObject obj, DiscordJar discordjv) { JSONArray stickerArray = obj.getJSONArray("stickers"); for (int i = 0; i < stickerArray.length(); i++) { - stickerList.add(Sticker.decompile(stickerArray.getJSONObject(i), discordjv)); + stickerList.add((Sticker) ModelDecoder.decodeObject(stickerArray.getJSONObject(i), Sticker.class, discordjv)); } stickers = stickerList; } catch (JSONException e) { diff --git a/src/main/java/com/seailz/discordjar/model/guild/verification/VerificationLevel.java b/src/main/java/com/seailz/discordjar/model/guild/verification/VerificationLevel.java index 2ca4c80c..32c1aa05 100644 --- a/src/main/java/com/seailz/discordjar/model/guild/verification/VerificationLevel.java +++ b/src/main/java/com/seailz/discordjar/model/guild/verification/VerificationLevel.java @@ -20,7 +20,7 @@ public enum VerificationLevel { // must have a verified phone number VERY_HIGH(4); - private final int code; + private int code; VerificationLevel(int code) { this.code = code; diff --git a/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreen.java b/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreen.java index 6629259b..bb40b05e 100644 --- a/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreen.java +++ b/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreen.java @@ -2,6 +2,8 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.core.Compilerable; +import com.seailz.discordjar.utils.model.JSONProp; +import com.seailz.discordjar.utils.model.Model; import org.json.JSONArray; import org.json.JSONObject; @@ -11,37 +13,21 @@ /** * Represents a welcome screen. * - * @param description The description of the welcome screen - * @param welcomeChannels The channels shown in the welcome screen */ -public record WelcomeScreen( - String description, - WelcomeScreenChannel[] welcomeChannels -) implements Compilerable { +public class WelcomeScreen implements Model { + @JSONProp("description") + private String description; + @JSONProp("welcome_channels") + private List welcomeChannels; - @Override - public JSONObject compile() { - JSONArray welcomeChannels = new JSONArray(); - for (WelcomeScreenChannel channel : welcomeChannels()) { - welcomeChannels.put(channel.compile()); - } + private WelcomeScreen () {} - return new JSONObject() - .put("description", description) - .put("welcome_channels", welcomeChannels); + public String description() { + return description; } - public static WelcomeScreen decompile(JSONObject obj, DiscordJar discordJar) { - List welcomeChannels = new ArrayList<>(); - JSONArray welcomeChannelsArray = obj.getJSONArray("welcome_channels"); - for (int i = 0; i < welcomeChannelsArray.length(); i++) { - welcomeChannels.add(WelcomeScreenChannel.decompile(welcomeChannelsArray.getJSONObject(i), discordJar)); - } - - return new WelcomeScreen( - obj.getString("description"), - welcomeChannels.toArray(new WelcomeScreenChannel[0]) - ); + public List welcomeChannels() { + return welcomeChannels; } } diff --git a/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreenChannel.java b/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreenChannel.java index a2c3a72e..24978d83 100644 --- a/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreenChannel.java +++ b/src/main/java/com/seailz/discordjar/model/guild/welcome/WelcomeScreenChannel.java @@ -3,40 +3,44 @@ import com.seailz.discordjar.DiscordJar; import com.seailz.discordjar.core.Compilerable; import com.seailz.discordjar.model.channel.Channel; +import com.seailz.discordjar.utils.model.DiscordJarProp; +import com.seailz.discordjar.utils.model.JSONProp; import org.json.JSONObject; import org.springframework.lang.NonNull; /** * Represents a welcome screen channel recommendation. - * - * @param channel The channel - * @param description The description of the channel - * @param emojiId - * @param emojiName */ -public record WelcomeScreenChannel( - Channel channel, - String description, - String emojiId, - String emojiName -) implements Compilerable { - - @Override - public JSONObject compile() { - return new JSONObject() - .put("channel_id", channel.id()) - .put("description", description) - .put("emoji_id", emojiId) - .put("emoji_name", emojiName); +public class WelcomeScreenChannel { + private Channel channel; + @JSONProp("channel_id") + private String channelId; + @JSONProp("description") + private String description; + @JSONProp("emoji_id") + private String emojiId; + @JSONProp("emoji_name") + private String emojiName; + @DiscordJarProp + private DiscordJar jar; + + private WelcomeScreenChannel() {} + + public Channel channel() { + if (channel == null) channel = jar.getChannelById(channelId); + return channel; + } + + public String description() { + return description; } - @NonNull - public static WelcomeScreenChannel decompile(JSONObject obj, DiscordJar discordJar) { - return new WelcomeScreenChannel( - discordJar.getChannelById(obj.getString("channel_id")), - obj.getString("description"), - obj.getString("emoji_id"), - obj.getString("emoji_name") - ); + public String emojiId() { + return emojiId; } + + public String emojiName() { + return emojiName; + } + } diff --git a/src/main/java/com/seailz/discordjar/model/interaction/data/ResolvedData.java b/src/main/java/com/seailz/discordjar/model/interaction/data/ResolvedData.java index 954c3220..a70a77ea 100644 --- a/src/main/java/com/seailz/discordjar/model/interaction/data/ResolvedData.java +++ b/src/main/java/com/seailz/discordjar/model/interaction/data/ResolvedData.java @@ -116,7 +116,7 @@ public static ResolvedData decompile(JSONObject obj, DiscordJar discordJar) { if (obj.has("roles") && !obj.isNull("roles")) { JSONObject rolesObj = obj.getJSONObject("roles"); for (String s : rolesObj.keySet()) { - roles.put(s, Role.decompile(rolesObj.getJSONObject(s))); + roles.put(s, (Role) ModelDecoder.decodeObject(rolesObj.getJSONObject(s), Role.class, discordJar)); } } else { roles = null; diff --git a/src/main/java/com/seailz/discordjar/model/invite/internal/InviteImpl.java b/src/main/java/com/seailz/discordjar/model/invite/internal/InviteImpl.java index 954379f8..e94515e1 100644 --- a/src/main/java/com/seailz/discordjar/model/invite/internal/InviteImpl.java +++ b/src/main/java/com/seailz/discordjar/model/invite/internal/InviteImpl.java @@ -39,7 +39,7 @@ public InviteImpl(String code, Guild guild, Channel channel, User inviter, Voice public static InviteImpl decompile(JSONObject obj, DiscordJar discordJar) { String code = obj.has("code") ? obj.getString("code") : null; - Guild guild = obj.has("guild") && obj.get("guild") != JSONObject.NULL ? Guild.decompile(obj.getJSONObject("guild"), discordJar) : null; + Guild guild = obj.has("guild") && obj.get("guild") != JSONObject.NULL ? (Guild) ModelDecoder.decodeObject(obj.getJSONObject("guild"), Guild.class, discordJar) : null; Channel channel = obj.has("channel") && obj.get("channel") != JSONObject.NULL ? Channel.decompile(obj.getJSONObject("channel"), discordJar) : null; User inviter = obj.has("inviter") && obj.get("inviter") != JSONObject.NULL ? (User) ModelDecoder.decodeObject(obj.getJSONObject("inviter"), User.class, discordJar) : null; VoiceInviteTargetType voiceInviteTarget = obj.has("target_type") ? VoiceInviteTargetType.fromCode(obj.getInt("target_type")) : null; diff --git a/src/main/java/com/seailz/discordjar/model/invite/internal/InviteMetadataImpl.java b/src/main/java/com/seailz/discordjar/model/invite/internal/InviteMetadataImpl.java index 6e4da780..f9413925 100644 --- a/src/main/java/com/seailz/discordjar/model/invite/internal/InviteMetadataImpl.java +++ b/src/main/java/com/seailz/discordjar/model/invite/internal/InviteMetadataImpl.java @@ -53,7 +53,7 @@ public String createdAt() { public static InviteMetadataImpl decompile(JSONObject obj, DiscordJar discordJar) { String code = obj.has("code") ? obj.getString("code") : null; - Guild guild = obj.has("guild") && obj.get("guild") != JSONObject.NULL ? Guild.decompile(obj.getJSONObject("guild"), discordJar) : null; + Guild guild = obj.has("guild") && obj.get("guild") != JSONObject.NULL ? (Guild) ModelDecoder.decodeObject(obj.getJSONObject("guild"), Guild.class, discordJar) : null; Channel channel = obj.has("channel") && obj.get("channel") != JSONObject.NULL ? Channel.decompile(obj.getJSONObject("channel"), discordJar) : null; User inviter = obj.has("inviter") && obj.get("inviter") != JSONObject.NULL ? (User) ModelDecoder.decodeObject(obj.getJSONObject("inviter"), User.class, discordJar) : null; VoiceInviteTargetType voiceInviteTarget = obj.has("target_type") ? VoiceInviteTargetType.fromCode(obj.getInt("target_type")) : null; diff --git a/src/main/java/com/seailz/discordjar/model/message/Message.java b/src/main/java/com/seailz/discordjar/model/message/Message.java index 92cd9419..7363aac0 100644 --- a/src/main/java/com/seailz/discordjar/model/message/Message.java +++ b/src/main/java/com/seailz/discordjar/model/message/Message.java @@ -196,7 +196,7 @@ public static Message decompile(JSONObject obj, DiscordJar discordJar) { JSONArray mentionRolesArray = obj.getJSONArray("mention_roles"); mentionRoles = new Role[mentionRolesArray.length()]; for (int i = 0; i < mentionRolesArray.length(); i++) { - mentionRoles[i] = Role.decompile(mentionRolesArray.getJSONObject(i)); + mentionRoles[i] = (Role) ModelDecoder.decodeObject(mentionRolesArray.getJSONObject(i), Role.class, discordJar); } } catch (JSONException e) { mentionRoles = null; diff --git a/src/main/java/com/seailz/discordjar/model/role/Role.java b/src/main/java/com/seailz/discordjar/model/role/Role.java index fae60397..75499b60 100644 --- a/src/main/java/com/seailz/discordjar/model/role/Role.java +++ b/src/main/java/com/seailz/discordjar/model/role/Role.java @@ -6,6 +6,8 @@ import com.seailz.discordjar.utils.Mentionable; import com.seailz.discordjar.utils.flag.BitwiseUtil; import com.seailz.discordjar.utils.flag.Bitwiseable; +import com.seailz.discordjar.utils.model.JSONProp; +import com.seailz.discordjar.utils.model.Model; import org.json.JSONException; import org.json.JSONObject; @@ -14,131 +16,81 @@ /** * Represents a Discord role in a guild. - * - * @param id The role's ID. - * @param name The role's name. - * @param color The role's color. - * @param hoist Whether the role is pinned in the user listing. - * @param icon The role's icon. - * @param position The role's position. - * @param permissions The role's permissions. - * @param managed Whether the role is managed by an integration. - * @param mentionable Whether the role is mentionable. - * @param tags The role's tags. */ -public record Role( - String id, - String name, - int color, - boolean hoist, - String icon, - int position, - int permissions, - boolean managed, - boolean mentionable, - RoleTag tags, - EnumSet flags, - int flagsRaw -) implements Compilerable, Resolvable, Mentionable { - public static Role decompile(JSONObject obj) { - String id; - String name; - int color; - boolean hoist; - String icon; - int position; - int permissions; - boolean managed; - boolean mentionable; - RoleTag tags; - EnumSet flags = EnumSet.noneOf(Flag.class); - int flagsRaw; - - try { - id = obj.getString("id"); - } catch (JSONException e) { - id = null; - } - - try { - name = obj.getString("name"); - } catch (JSONException e) { - name = null; - } +public class Role implements Resolvable, Mentionable, Model { + @JSONProp("id") + private String id; + @JSONProp("name") + private String name; + @JSONProp("color") + private int color; + @JSONProp("hoist") + private boolean hoist; + @JSONProp("icon") + private String icon; + @JSONProp("position") + private int position; + @JSONProp("permissions") + private int permissions; // TODO: make this a set of permissions + @JSONProp("managed") + private boolean managed; + @JSONProp("mentionable") + private boolean mentionable; + @JSONProp("tags") + private RoleTag tags; + @JSONProp("flags") + private EnumSet flags; + @JSONProp("flags") + private int flagsRaw; + + private Role() {} + + public String id() { + return id; + } - try { - color = obj.getInt("color"); - } catch (JSONException e) { - color = 0; - } + public String name() { + return name; + } - try { - hoist = obj.getBoolean("hoist"); - } catch (JSONException e) { - hoist = false; - } + public int color() { + return color; + } - try { - icon = obj.getString("icon"); - } catch (JSONException e) { - icon = null; - } + public boolean hoist() { + return hoist; + } - try { - position = obj.getInt("position"); - } catch (JSONException e) { - position = 0; - } + public String icon() { + return icon; + } - try { - permissions = obj.getInt("permissions"); - } catch (JSONException e) { - permissions = 0; - } + public int position() { + return position; + } - try { - managed = obj.getBoolean("managed"); - } catch (JSONException e) { - managed = false; - } + public int permissions() { + return permissions; + } - try { - mentionable = obj.getBoolean("mentionable"); - } catch (JSONException e) { - mentionable = false; - } + public boolean managed() { + return managed; + } - try { - tags = RoleTag.decompile(obj.getJSONObject("tags")); - } catch (JSONException e) { - tags = null; - } + public boolean mentionable() { + return mentionable; + } - try { - flagsRaw = obj.getInt("flags"); - flags = new BitwiseUtil().get(flagsRaw, Role.Flag.class); - } catch (JSONException e) { - flagsRaw = 0; - } + public RoleTag tags() { + return tags; + } - return new Role(id, name, color, hoist, icon, position, permissions, managed, mentionable, tags, flags, flagsRaw); + public EnumSet flags() { + return flags; } - @Override - public JSONObject compile() { - JSONObject obj = new JSONObject(); - obj.put("id", id); - obj.put("name", name); - obj.put("color", color); - obj.put("hoist", hoist); - obj.put("icon", icon); - obj.put("position", position); - obj.put("permissions", permissions); - obj.put("managed", managed); - obj.put("mentionable", mentionable); - obj.put("tags", tags.compile()); - obj.put("flags", flags); - return obj; + public int flagsRaw() { + return flagsRaw; } @Override diff --git a/src/main/java/com/seailz/discordjar/model/role/RoleTag.java b/src/main/java/com/seailz/discordjar/model/role/RoleTag.java index 6a58ac2e..cb3fe193 100644 --- a/src/main/java/com/seailz/discordjar/model/role/RoleTag.java +++ b/src/main/java/com/seailz/discordjar/model/role/RoleTag.java @@ -1,43 +1,48 @@ package com.seailz.discordjar.model.role; import com.seailz.discordjar.core.Compilerable; +import com.seailz.discordjar.utils.model.JSONProp; +import com.seailz.discordjar.utils.model.Model; import org.json.JSONObject; import org.springframework.lang.NonNull; -public record RoleTag( - String botId, - String integrationId, - boolean isPremiumSubscriber, - String subscriptionListingId, // the id of this role's subscription sku and listing - boolean availableForPurchase, // whether this role is available for purchase - boolean guildConnections // whether this role is a guild's linked role -) implements Compilerable { - - @Override - public JSONObject compile() { - return new JSONObject() - .put("bot_id", botId) - .put("integration_id", integrationId) - .put("is_premium_subscriber", isPremiumSubscriber); +public class RoleTag implements Model { + @JSONProp("bot_id") + private String botId; + @JSONProp("integration_id") + private String integrationId; + @JSONProp("premium_subscriber") + private boolean isPremiumSubscriber; + @JSONProp("subscription_listing_id") + private String subscriptionListingId; + @JSONProp("available_for_purchase") + private boolean availableForPurchase; + @JSONProp("guild_connections") + private boolean guildConnections; + + private RoleTag() {} + + public String botId() { + return botId; } - @NonNull - public static RoleTag decompile(JSONObject obj) { - String botId = null; - String integrationId = null; - boolean isPremiumSubscriber; - String subscriptionListingId = null; - boolean availableForPurchase = false; - boolean guildConnections = false; - - if (obj.has("bot_id") && !obj.isNull("bot_id")) botId = obj.getString("bot_id"); - if (obj.has("integration_id") && !obj.isNull("integration_id")) integrationId = obj.getString("integration_id"); - if (obj.has("subscription_listing_id") && !obj.isNull("subscription_listing_id")) subscriptionListingId = obj.getString("subscription_listing_id"); - isPremiumSubscriber = obj.has("premium_subscriber"); - availableForPurchase = obj.has("available_for_purchase"); - guildConnections = obj.has("guild_connections"); - - return new RoleTag(botId, integrationId, isPremiumSubscriber, subscriptionListingId, availableForPurchase, guildConnections); + public String integrationId() { + return integrationId; } + public boolean isPremiumSubscriber() { + return isPremiumSubscriber; + } + + public String subscriptionListingId() { + return subscriptionListingId; + } + + public boolean availableForPurchase() { + return availableForPurchase; + } + + public boolean guildConnections() { + return guildConnections; + } } diff --git a/src/main/java/com/seailz/discordjar/model/status/activity/Activity.java b/src/main/java/com/seailz/discordjar/model/status/activity/Activity.java index 515b845c..56f92a72 100644 --- a/src/main/java/com/seailz/discordjar/model/status/activity/Activity.java +++ b/src/main/java/com/seailz/discordjar/model/status/activity/Activity.java @@ -4,6 +4,7 @@ import com.seailz.discordjar.core.Compilerable; import com.seailz.discordjar.model.emoji.Emoji; import com.seailz.discordjar.model.status.Status; +import com.seailz.discordjar.utils.model.ModelDecoder; import org.jetbrains.annotations.NotNull; import org.json.JSONObject; @@ -140,7 +141,7 @@ public static Activity decompile(JSONObject obj, DiscordJar discordJar) { if (obj.has("application_id")) applicationId = obj.getString("application_id"); else applicationId = null; - if (obj.has("emoji")) emoji = Emoji.decompile(obj.getJSONObject("emoji"), discordJar); + if (obj.has("emoji")) emoji = (Emoji) ModelDecoder.decodeObject(obj.getJSONObject("emoji"), Emoji.class, discordJar); else emoji = null; if (obj.has("instance")) instance = obj.getBoolean("instance"); diff --git a/src/main/java/com/seailz/discordjar/model/team/Team.java b/src/main/java/com/seailz/discordjar/model/team/Team.java index bbfba36a..40267864 100644 --- a/src/main/java/com/seailz/discordjar/model/team/Team.java +++ b/src/main/java/com/seailz/discordjar/model/team/Team.java @@ -24,19 +24,7 @@ public class Team implements Compilerable, Snowflake, Model { @JSONProp("owner_user_id") private String ownerUserId; - public Team( - String icon, - String id, - String name, - List members, - String ownerUserId - ) { - this.icon = icon; - this.id = id; - this.name = name; - this.members = members; - this.ownerUserId = ownerUserId; - } + private Team() {} public String icon() { return icon; diff --git a/src/main/java/com/seailz/discordjar/utils/model/ModelDecoder.java b/src/main/java/com/seailz/discordjar/utils/model/ModelDecoder.java index 1e70f77e..00399c7f 100644 --- a/src/main/java/com/seailz/discordjar/utils/model/ModelDecoder.java +++ b/src/main/java/com/seailz/discordjar/utils/model/ModelDecoder.java @@ -1,6 +1,7 @@ package com.seailz.discordjar.utils.model; import com.seailz.discordjar.DiscordJar; +import com.seailz.discordjar.model.guild.GuildFeature; import com.seailz.discordjar.utils.flag.BitwiseUtil; import com.seailz.discordjar.utils.flag.Bitwiseable; import org.json.JSONArray; @@ -68,7 +69,7 @@ public static Model decodeObject(JSONObject json, Class model, if (!json.has(prop.value())) continue; Enum decodedEnum = null; try { - decodedEnum = decodeEnum((Class) field.getType(), get(json, prop.value())); + decodedEnum = decodeEnum((Class) field.getType(), get(json, prop.value(), field.getType())); } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } @@ -90,6 +91,21 @@ public static Model decodeObject(JSONObject json, Class model, Type[] argTypes = paramType.getActualTypeArguments(); Class enumClass = (Class) argTypes[0]; + if (enumClass.equals(GuildFeature.class)) { + EnumSet set = null; + String[] arr = json.getJSONArray(prop.value()).toList().toArray( + new String[0] + ); + + set = GuildFeature.getGuildFeatures(arr); + try { + field.set(inst, set); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + continue; + } + // If enumClass extends Bitwiseable, we want to decode it as a Bitwiseable. if (Bitwiseable.class.isAssignableFrom(enumClass)) { BitwiseUtil bitwiseUtil = new BitwiseUtil(); @@ -123,7 +139,7 @@ public static Model decodeObject(JSONObject json, Class model, continue; } - if (!(get(json, prop.value()) instanceof JSONArray)) continue; + if (!(get(json, prop.value(), field.getType()) instanceof JSONArray)) continue; List ls = null; try { @@ -139,7 +155,7 @@ public static Model decodeObject(JSONObject json, Class model, } } else { if (!json.has(prop.value())) continue; - if (!(get(json, prop.value()) instanceof JSONObject)) continue; + if (!(get(json, prop.value(), field.getType()) instanceof JSONObject)) continue; try { field.set(inst, decodeObject(json.getJSONObject(prop.value()), (Class) field.getType(), discordJar)); } catch (IllegalAccessException e) { @@ -151,7 +167,7 @@ public static Model decodeObject(JSONObject json, Class model, if (json.has(prop.value())) { try { - field.set(inst, get(json, prop.value())); + field.set(inst, get(json, prop.value(), field.getType())); } catch (IllegalAccessException e) { throw new RuntimeException(e); } @@ -193,7 +209,9 @@ private static Enum decodeEnum(Class enumClass, Object value) } } else { for (Object e : enumClass.getEnumConstants()) { - if (e.getClass().getDeclaredField(valueFieldName).getInt(e) == (int) value) { + Field field = e.getClass().getDeclaredField(valueFieldName); + field.setAccessible(true); + if (field.getInt(e) == (int) value) { return (Enum) e; } } @@ -216,7 +234,25 @@ private static List decodeArray(JSONArray arr, Field field, DiscordJar djar) } return Arrays.asList(arr1); } - private static Object get(JSONObject in, String key) { - return in.has(key) ? (in.get(key).equals(JSONObject.NULL) ? null : in.get(key)) : null; + private static Object get(JSONObject in, String key, Class expectedType) { + Object nullValue = null; + + // If expectedType is a primitive, set nullValue to the default value for that primitive. + if (expectedType == boolean.class) { + nullValue = false; + } else if (expectedType == byte.class + || expectedType == short.class + || expectedType == int.class + || expectedType == long.class + || expectedType == float.class + || expectedType == double.class) { + nullValue = 0; + } else if (expectedType == char.class) { + nullValue = '\u0000'; + } + + if (!in.has(key)) return nullValue; + if (in.get(key).equals(JSONObject.NULL)) return nullValue; + return in.get(key); } }