diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java
index ad2ba5dae1..31688a61c3 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java
@@ -1,11 +1,11 @@
package org.mage.plugins.card.dl.sources;
import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import mage.MageException;
import mage.client.util.CardLanguage;
+import mage.util.JsonUtil;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
@@ -174,14 +174,18 @@ public enum ScryfallImageSource implements CardImageSource {
// OK, found card data, parse it
JsonObject jsonCard = JsonParser.parseReader(new InputStreamReader(jsonStream)).getAsJsonObject();
- if (!jsonCard.has("card_faces")) {
+ JsonArray jsonFaces = JsonUtil.getAsArray(jsonCard, "card_faces");
+ if (jsonFaces == null) {
throw new MageException("Couldn't find card_faces in card's JSON data: " + jsonUrl);
}
- JsonArray jsonCardFaces = jsonCard.getAsJsonArray("card_faces");
- JsonObject jsonCardFace = jsonCardFaces.get(card.isSecondSide() ? 1 : 0).getAsJsonObject();
- JsonObject jsonImageUris = jsonCardFace.getAsJsonObject("image_uris");
- return jsonImageUris.get("large").getAsString();
+ JsonObject jsonFace = jsonFaces.get(card.isSecondSide() ? 1 : 0).getAsJsonObject();
+ JsonObject jsonImages = JsonUtil.getAsObject(jsonFace, "image_uris");
+ if (jsonImages == null) {
+ throw new MageException("Couldn't find image_uris in card's JSON data: " + jsonUrl);
+ }
+
+ return JsonUtil.getAsString(jsonImages, "large");
}
@Override
diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml
index aeb8fc37bb..4173847a93 100644
--- a/Mage.Common/pom.xml
+++ b/Mage.Common/pom.xml
@@ -26,12 +26,6 @@
jspf-core
0.9.1
-
-
- com.google.code.gson
- gson
- 2.8.8
-
org.jboss.remoting
@@ -61,6 +55,11 @@
1.0.2
+
+ log4j
+ log4j
+
+
org.junit.jupiter
junit-jupiter
diff --git a/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java b/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java
index 5e5ad8c2cd..c859b98ff0 100644
--- a/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java
+++ b/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java
@@ -1,6 +1,5 @@
package mage.cards.a;
-import com.google.common.collect.Sets;
import mage.MageInt;
import mage.abilities.Abilities;
import mage.abilities.Ability;
@@ -17,6 +16,8 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@@ -66,7 +67,7 @@ public final class AkromaVisionOfIxidor extends CardImpl {
class AkromaVisionOfIxidorEffect extends OneShotEffect {
- private static final Set> classes = Sets.newHashSet(
+ private static final Set> classes = new HashSet<>(Arrays.asList(
FlyingAbility.class,
FirstStrikeAbility.class,
DoubleStrikeAbility.class,
@@ -81,7 +82,7 @@ class AkromaVisionOfIxidorEffect extends OneShotEffect {
TrampleAbility.class,
VigilanceAbility.class,
PartnerAbility.class
- );
+ ));
AkromaVisionOfIxidorEffect() {
super(Outcome.Benefit);
diff --git a/Mage.Sets/src/mage/cards/c/ConfrontThePast.java b/Mage.Sets/src/mage/cards/c/ConfrontThePast.java
index 19b1507a8f..8cafe8f05d 100644
--- a/Mage.Sets/src/mage/cards/c/ConfrontThePast.java
+++ b/Mage.Sets/src/mage/cards/c/ConfrontThePast.java
@@ -1,6 +1,5 @@
package mage.cards.c;
-import com.google.common.collect.Iterables;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
@@ -65,7 +64,8 @@ enum ConfrontThePastAdjuster implements TargetAdjuster {
@Override
public void adjustTargets(Ability ability, Game game) {
- if (Iterables.getOnlyElement(ability.getEffects()) instanceof ReturnFromGraveyardToBattlefieldTargetEffect) {
+ if (ability.getEffects().size() == 1
+ && ability.getEffects().get(0) instanceof ReturnFromGraveyardToBattlefieldTargetEffect) {
int xValue = ability.getManaCostsToPay().getX();
ability.getTargets().clear();
FilterPermanentCard filter = new FilterPermanentCard("planeswalker card with mana value X or less");
diff --git a/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java b/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java
index 51900dabba..422f92a1d2 100644
--- a/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java
+++ b/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java
@@ -1,6 +1,5 @@
package mage.cards.e;
-import com.google.common.collect.Sets;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
@@ -22,6 +21,7 @@ import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
+import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -109,7 +109,10 @@ class EcologicalAppreciationEffect extends OneShotEffect {
Set disallowedCards = this.getTargets().stream()
.map(game::getCard)
.collect(Collectors.toSet());
- return isValidTarget(card, Sets.union(disallowedCards, cards.getCards(game)));
+ Set checkList = new HashSet<>();
+ checkList.addAll(disallowedCards);
+ checkList.addAll(cards.getCards(game));
+ return isValidTarget(card, checkList);
}
};
targetCardsInGY.setNotTarget(true);
diff --git a/Mage.Sets/src/mage/cards/k/KitesailSkirmisher.java b/Mage.Sets/src/mage/cards/k/KitesailSkirmisher.java
index 87ce26c7c3..8c0a523149 100644
--- a/Mage.Sets/src/mage/cards/k/KitesailSkirmisher.java
+++ b/Mage.Sets/src/mage/cards/k/KitesailSkirmisher.java
@@ -1,6 +1,5 @@
package mage.cards.k;
-import com.google.common.base.Objects;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@@ -22,6 +21,7 @@ import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.Game;
import mage.target.TargetPermanent;
+import java.util.Objects;
import java.util.UUID;
/**
@@ -74,7 +74,7 @@ enum KitesailSkirmisherPredicate implements ObjectSourcePlayerPredicate input, Game game) {
- return Objects.equal(
+ return Objects.equals(
game.getCombat().getDefenderId(input.getSourceId()),
game.getCombat().getDefenderId(input.getObject().getId())
);
diff --git a/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java b/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java
index 720399c292..fde6ef9fbe 100644
--- a/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java
+++ b/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java
@@ -35,8 +35,6 @@ import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
-import static com.google.common.collect.Iterables.getOnlyElement;
-
/**
* @author htrajan
*/
@@ -97,8 +95,7 @@ class TayamLuminousEnigmaCost extends RemoveCounterCost {
Player controller = game.getPlayer(controllerId);
for (int i = 0; i < countersToRemove; i++) {
if (target.choose(Outcome.UnboostCreature, controllerId, source.getSourceId(), game)) {
- UUID targetId = getOnlyElement(target.getTargets());
- Permanent permanent = game.getPermanent(targetId);
+ Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null) {
if (!permanent.getCounters(game).isEmpty()) {
String counterName = null;
diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/JsonGsonTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/JsonGsonTest.java
index 9ce4cb2f41..ec546ada70 100644
--- a/Mage.Tests/src/test/java/org/mage/test/utils/JsonGsonTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/utils/JsonGsonTest.java
@@ -3,6 +3,7 @@ package org.mage.test.utils;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
+import mage.util.JsonUtil;
import org.junit.Assert;
import org.junit.Test;
@@ -25,10 +26,17 @@ public class JsonGsonTest {
try {
// low level parser for unknown data structure
JsonObject json = JsonParser.parseReader(new FileReader(sampleFileName)).getAsJsonObject();
- Assert.assertEquals("Unknown data", "card", json.get("object").getAsString());
- JsonArray jsonFaces = json.getAsJsonArray("card_faces");
+
+ // data types
+ Assert.assertEquals("string", "card", JsonUtil.getAsString(json, "object"));
+ JsonArray jsonFaces = JsonUtil.getAsArray(json, "card_faces");
+ Assert.assertEquals("int", 60370, JsonUtil.getAsInt(json, "mtgo_id"));
+ Assert.assertTrue("boolean", JsonUtil.getAsBoolean(json, "highres_image"));
+ Assert.assertEquals("double", 4.0, JsonUtil.getAsDouble(json, "cmc"), 0.0);
+ Assert.assertNotNull("array", jsonFaces);
+
Assert.assertEquals("Card must have 2 faces", 2, jsonFaces.size());
- Assert.assertEquals("Unknown second side", "Infectious Curse", jsonFaces.get(1).getAsJsonObject().get("name").getAsString());
+ Assert.assertEquals("Unknown second side", "Infectious Curse", JsonUtil.getAsString(jsonFaces.get(1).getAsJsonObject(), "name"));
} catch (IOException e) {
e.printStackTrace();
Assert.fail("Can't load sample json file: " + sampleFileName);
diff --git a/Mage/pom.xml b/Mage/pom.xml
index 714e344652..7eb30b9a71 100644
--- a/Mage/pom.xml
+++ b/Mage/pom.xml
@@ -14,11 +14,6 @@
Mage Framework
-
- com.googlecode.json-simple
- json-simple
- 1.1.1
-
log4j
log4j
@@ -34,6 +29,10 @@
com.google.guava
guava
+
+ com.google.code.gson
+ gson
+
com.j256.ormlite
ormlite-jdbc
diff --git a/Mage/src/main/java/mage/cards/decks/importer/CodDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/CodDeckImporter.java
index e518e5ea79..383f917ef2 100644
--- a/Mage/src/main/java/mage/cards/decks/importer/CodDeckImporter.java
+++ b/Mage/src/main/java/mage/cards/decks/importer/CodDeckImporter.java
@@ -22,9 +22,9 @@ public class CodDeckImporter extends XmlDeckImporter {
* @return
*/
@Override
- public DeckCardLists importDeck(String filename, StringBuilder errorMessages, boolean saveAutoFixedFile) {
+ public DeckCardLists importDeck(String fileName, StringBuilder errorMessages, boolean saveAutoFixedFile) {
try {
- Document doc = getXmlDocument(filename);
+ Document doc = getXmlDocument(fileName);
DeckCardLists decklist = new DeckCardLists();
List mainCards = getNodes(doc, "/cockatrice_deck/zone[@name='main']/card");
diff --git a/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java
index 26785c1909..57bc486956 100644
--- a/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java
+++ b/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java
@@ -86,10 +86,10 @@ public abstract class DeckImporter {
}
}
- public abstract DeckCardLists importDeck(String file, StringBuilder errorMessages, boolean saveAutoFixedFile);
+ public abstract DeckCardLists importDeck(String fileName, StringBuilder errorMessages, boolean saveAutoFixedFile);
- public DeckCardLists importDeck(String file, boolean saveAutoFixedFile) {
- return importDeck(file, new StringBuilder(), saveAutoFixedFile);
+ public DeckCardLists importDeck(String fileName, boolean saveAutoFixedFile) {
+ return importDeck(fileName, new StringBuilder(), saveAutoFixedFile);
}
public CardLookup getCardLookup() {
diff --git a/Mage/src/main/java/mage/cards/decks/importer/JsonDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/JsonDeckImporter.java
index 9e5a7e52cc..1502f29133 100644
--- a/Mage/src/main/java/mage/cards/decks/importer/JsonDeckImporter.java
+++ b/Mage/src/main/java/mage/cards/decks/importer/JsonDeckImporter.java
@@ -1,9 +1,7 @@
package mage.cards.decks.importer;
+import com.google.gson.*;
import mage.cards.decks.DeckCardLists;
-import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
-import org.json.simple.parser.ParseException;
import java.io.File;
import java.io.FileReader;
@@ -16,26 +14,25 @@ public abstract class JsonDeckImporter extends DeckImporter {
protected StringBuilder sbMessage = new StringBuilder();
/**
- * @param file file to import
+ * @param fileName file to import
* @param errorMessages you can setup output messages to showup to user
* @param saveAutoFixedFile do not supported for that format
* @return decks list
*/
- public DeckCardLists importDeck(String file, StringBuilder errorMessages, boolean saveAutoFixedFile) {
- File f = new File(file);
+ public DeckCardLists importDeck(String fileName, StringBuilder errorMessages, boolean saveAutoFixedFile) {
+ File f = new File(fileName);
DeckCardLists deckList = new DeckCardLists();
if (!f.exists()) {
- logger.warn("Deckfile " + file + " not found.");
+ logger.warn("Deckfile " + fileName + " not found.");
return deckList;
}
sbMessage.setLength(0);
try {
try (FileReader reader = new FileReader(f)) {
- try { // Json parsing
- JSONParser parser = new JSONParser();
- JSONObject rootObj = (JSONObject) parser.parse(reader);
- readJson(rootObj, deckList);
+ try {
+ JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
+ readJson(json, deckList);
if (sbMessage.length() > 0) {
if (errorMessages != null) {
@@ -46,8 +43,8 @@ public abstract class JsonDeckImporter extends DeckImporter {
logger.fatal(sbMessage);
}
}
- } catch (ParseException ex) {
- logger.fatal(null, ex);
+ } catch (JsonParseException ex) {
+ logger.fatal("Can't parse json-deck: " + fileName, ex);
}
} catch (Exception ex) {
logger.fatal(null, ex);
@@ -59,9 +56,9 @@ public abstract class JsonDeckImporter extends DeckImporter {
}
@Override
- public DeckCardLists importDeck(String file, boolean saveAutoFixedFile) {
- return importDeck(file, null, saveAutoFixedFile);
+ public DeckCardLists importDeck(String fileName, boolean saveAutoFixedFile) {
+ return importDeck(fileName, null, saveAutoFixedFile);
}
- protected abstract void readJson(JSONObject line, DeckCardLists decklist);
+ protected abstract void readJson(JsonObject json, DeckCardLists decklist);
}
diff --git a/Mage/src/main/java/mage/cards/decks/importer/MtgjsonDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/MtgjsonDeckImporter.java
index de0e800518..5a0cc5371e 100644
--- a/Mage/src/main/java/mage/cards/decks/importer/MtgjsonDeckImporter.java
+++ b/Mage/src/main/java/mage/cards/decks/importer/MtgjsonDeckImporter.java
@@ -1,10 +1,11 @@
package mage.cards.decks.importer;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
import mage.cards.decks.DeckCardInfo;
import mage.cards.decks.DeckCardLists;
import mage.cards.repository.CardInfo;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
+import mage.util.JsonUtil;
import java.util.List;
import java.util.Optional;
@@ -16,39 +17,45 @@ import java.util.Optional;
public class MtgjsonDeckImporter extends JsonDeckImporter {
@Override
- protected void readJson(JSONObject rootObj, DeckCardLists deckList) {
- JSONObject data = (JSONObject) rootObj.get("data");
+ protected void readJson(JsonObject json, DeckCardLists deckList) {
+ JsonObject data = JsonUtil.getAsObject(json, "data");
if (data == null) {
sbMessage.append("Could not find data in json").append("'\n");
return;
}
// info
- String deckSet = (String) data.get("code");
- String name = (String) data.get("name");
- if (name != null) {
+ String deckSet = JsonUtil.getAsString(data, "code");
+ String name = JsonUtil.getAsString(data, "name");
+ if (!name.isEmpty()) {
deckList.setName(name);
}
+
// mainboard
- JSONArray mainBoard = (JSONArray) data.get("mainBoard");
+ JsonArray mainBoard = JsonUtil.getAsArray(data, "mainBoard");
List mainDeckList = deckList.getCards();
addBoardToList(mainBoard, mainDeckList, deckSet);
+
// sideboard
- JSONArray sideBoard = (JSONArray) data.get("sideBoard");
+ JsonArray sideBoard = JsonUtil.getAsArray(data, "sideBoard");
List sideDeckList = deckList.getSideboard();
addBoardToList(sideBoard, sideDeckList, deckSet);
}
- private void addBoardToList(JSONArray board, List list, String deckSet) {
+ private void addBoardToList(JsonArray board, List list, String deckSet) {
+ if (board == null || board.isEmpty()) {
+ return;
+ }
+
board.forEach(arrayCard -> {
- JSONObject card = (JSONObject) arrayCard;
- String name = (String) card.get("name");
- String setCode = (String) card.get("setCode");
- if (setCode == null || setCode.isEmpty()) {
+ JsonObject card = (JsonObject) arrayCard;
+ String name = JsonUtil.getAsString(card, "name");
+ String setCode = JsonUtil.getAsString(card, "setCode");
+ if (setCode.isEmpty()) {
setCode = deckSet;
}
- int num = ((Number) card.get("count")).intValue();
+ int num = JsonUtil.getAsInt(card, "count");
Optional cardLookup = getCardLookup().lookupCardInfo(name, setCode);
if (!cardLookup.isPresent()) {
sbMessage.append("Could not find card: '").append(name).append("'\n");
diff --git a/Mage/src/main/java/mage/cards/decks/importer/O8dDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/O8dDeckImporter.java
index 3426f57c6f..1a98f0454f 100644
--- a/Mage/src/main/java/mage/cards/decks/importer/O8dDeckImporter.java
+++ b/Mage/src/main/java/mage/cards/decks/importer/O8dDeckImporter.java
@@ -22,9 +22,9 @@ public class O8dDeckImporter extends XmlDeckImporter {
* @return
*/
@Override
- public DeckCardLists importDeck(String filename, StringBuilder errorMessages, boolean saveAutoFixedFile) {
+ public DeckCardLists importDeck(String fileName, StringBuilder errorMessages, boolean saveAutoFixedFile) {
try {
- Document doc = getXmlDocument(filename);
+ Document doc = getXmlDocument(fileName);
DeckCardLists decklist = new DeckCardLists();
List mainCards = getNodes(doc, "/deck/section[@name='Main']/card");
diff --git a/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java
index c6fd9a996f..86c7965185 100644
--- a/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java
+++ b/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java
@@ -26,13 +26,13 @@ public abstract class PlainTextDeckImporter extends DeckImporter {
* @param saveAutoFixedFile save fixed deck file (if any fixes applied)
* @return decks list
*/
- public DeckCardLists importDeck(String file, StringBuilder errorMessages, boolean saveAutoFixedFile) {
- File f = new File(file);
+ public DeckCardLists importDeck(String fileName, StringBuilder errorMessages, boolean saveAutoFixedFile) {
+ File f = new File(fileName);
List originalFile = new ArrayList<>();
List fixedFile = new ArrayList<>();
DeckCardLists deckList = new DeckCardLists();
if (!f.exists()) {
- logger.warn("Deckfile " + file + " not found.");
+ logger.warn("Deckfile " + fileName + " not found.");
return deckList;
}
lineCount = 0;
@@ -94,8 +94,8 @@ public abstract class PlainTextDeckImporter extends DeckImporter {
@Override
- public DeckCardLists importDeck(String file, boolean saveAutoFixedFile) {
- return importDeck(file, null, saveAutoFixedFile);
+ public DeckCardLists importDeck(String fileName, boolean saveAutoFixedFile) {
+ return importDeck(fileName, null, saveAutoFixedFile);
}
/**
diff --git a/Mage/src/main/java/mage/util/JsonUtil.java b/Mage/src/main/java/mage/util/JsonUtil.java
new file mode 100644
index 0000000000..6455d139a8
--- /dev/null
+++ b/Mage/src/main/java/mage/util/JsonUtil.java
@@ -0,0 +1,50 @@
+package mage.util;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+
+/**
+ * @author JayDi85
+ */
+public class JsonUtil {
+
+ public static JsonObject getAsObject(JsonObject json, String field) {
+ return json.has(field) ? json.get(field).getAsJsonObject() : null;
+ }
+
+ public static JsonArray getAsArray(JsonObject json, String field) {
+ return json.has(field) ? json.get(field).getAsJsonArray() : null;
+ }
+
+ public static String getAsString(JsonObject json, String field) {
+ return getAsString(json, field, "");
+ }
+
+ public static String getAsString(JsonObject json, String field, String nullValue) {
+ return json.has(field) ? json.get(field).getAsString() : nullValue;
+ }
+
+ public static int getAsInt(JsonObject json, String field) {
+ return getAsInt(json, field, 0);
+ }
+
+ public static int getAsInt(JsonObject json, String field, int nullValue) {
+ return json.has(field) ? json.get(field).getAsInt() : nullValue;
+ }
+
+ public static double getAsDouble(JsonObject json, String field) {
+ return getAsDouble(json, field, 0.0);
+ }
+
+ public static double getAsDouble(JsonObject json, String field, double nullValue) {
+ return json.has(field) ? json.get(field).getAsDouble() : nullValue;
+ }
+
+ public static boolean getAsBoolean(JsonObject json, String field) {
+ return getAsBoolean(json, field, false);
+ }
+
+ public static boolean getAsBoolean(JsonObject json, String field, boolean nullValue) {
+ return json.has(field) ? json.get(field).getAsBoolean() : nullValue;
+ }
+}
diff --git a/pom.xml b/pom.xml
index 505fdc766a..7d1aab37be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -174,6 +174,12 @@
slf4j-log4j12
1.8.0-beta2
+
+
+ com.google.code.gson
+ gson
+ 2.8.8
+
com.google.guava
guava