Fixed the package structure
This commit is contained in:
292
src/org/mcteam/factions/Board.java
Normal file
292
src/org/mcteam/factions/Board.java
Normal file
@ -0,0 +1,292 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.logging.Level;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.mcteam.factions.gson.JsonArray;
|
||||
import org.mcteam.factions.gson.JsonElement;
|
||||
import org.mcteam.factions.gson.JsonObject;
|
||||
import org.mcteam.factions.gson.JsonParser;
|
||||
import org.mcteam.factions.gson.reflect.TypeToken;
|
||||
import org.mcteam.factions.util.AsciiCompass;
|
||||
import org.mcteam.factions.util.DiscUtil;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
|
||||
public class Board {
|
||||
private static transient File file = new File(Factions.instance.getDataFolder(), "board.json");
|
||||
private static transient HashMap<FLocation, Integer> flocationIds = new HashMap<FLocation, Integer>();
|
||||
|
||||
//----------------------------------------------//
|
||||
// Get and Set
|
||||
//----------------------------------------------//
|
||||
public static int getIdAt(FLocation flocation) {
|
||||
if ( ! flocationIds.containsKey(flocation)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return flocationIds.get(flocation);
|
||||
}
|
||||
|
||||
public static Faction getFactionAt(FLocation flocation) {
|
||||
return Faction.get(getIdAt(flocation));
|
||||
}
|
||||
|
||||
public static void setIdAt(int id, FLocation flocation) {
|
||||
if (id == 0) {
|
||||
removeAt(flocation);
|
||||
}
|
||||
|
||||
flocationIds.put(flocation, id);
|
||||
}
|
||||
|
||||
public static void setFactionAt(Faction faction, FLocation flocation) {
|
||||
setIdAt(faction.getId(), flocation);
|
||||
}
|
||||
|
||||
public static void removeAt(FLocation flocation) {
|
||||
flocationIds.remove(flocation);
|
||||
}
|
||||
|
||||
// Is this coord NOT completely surrounded by coords claimed by the same faction?
|
||||
// Simpler: Is there any nearby coord with a faction other than the faction here?
|
||||
public static boolean isBorderLocation(FLocation flocation) {
|
||||
Faction faction = getFactionAt(flocation);
|
||||
FLocation a = flocation.getRelative(1, 0);
|
||||
FLocation b = flocation.getRelative(-1, 0);
|
||||
FLocation c = flocation.getRelative(0, 1);
|
||||
FLocation d = flocation.getRelative(0, -1);
|
||||
return faction != getFactionAt(a) || faction != getFactionAt(b) || faction != getFactionAt(c) || faction != getFactionAt(d);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------//
|
||||
// Cleaner. Remove orphaned foreign keys
|
||||
//----------------------------------------------//
|
||||
|
||||
public static void clean() {
|
||||
Iterator<Entry<FLocation, Integer>> iter = flocationIds.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entry<FLocation, Integer> entry = iter.next();
|
||||
if ( ! Faction.exists(entry.getValue())) {
|
||||
Factions.log("Board cleaner removed "+entry.getValue()+" from "+entry.getKey());
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Coord count
|
||||
//----------------------------------------------//
|
||||
|
||||
public static int getFactionCoordCount(int factionId) {
|
||||
int ret = 0;
|
||||
for (int thatFactionId : flocationIds.values()) {
|
||||
if(thatFactionId == factionId) {
|
||||
ret += 1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static int getFactionCoordCount(Faction faction) {
|
||||
return getFactionCoordCount(faction.getId());
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Map generation
|
||||
//----------------------------------------------//
|
||||
|
||||
/**
|
||||
* The map is relative to a coord and a faction
|
||||
* north is in the direction of decreasing x
|
||||
* east is in the direction of decreasing z
|
||||
*/
|
||||
public static ArrayList<String> getMap(Faction faction, FLocation flocation, double inDegrees) {
|
||||
ArrayList<String> ret = new ArrayList<String>();
|
||||
ret.add(TextUtil.titleize("("+flocation.getCoordString()+") "+getFactionAt(flocation).getTag(faction)));
|
||||
|
||||
int halfWidth = Conf.mapWidth / 2;
|
||||
int halfHeight = Conf.mapHeight / 2;
|
||||
FLocation topLeft = flocation.getRelative(-halfHeight, halfWidth);
|
||||
int width = halfWidth * 2 + 1;
|
||||
int height = halfHeight * 2 + 1;
|
||||
|
||||
// For each row
|
||||
for (int dx = 0; dx < height; dx++) {
|
||||
// Draw and add that row
|
||||
String row = "";
|
||||
for (int dz = 0; dz > -width; dz--) {
|
||||
if(dz == -(halfWidth) && dx == halfHeight) {
|
||||
row += ChatColor.AQUA+"+";
|
||||
} else {
|
||||
FLocation flocationHere = topLeft.getRelative(dx, dz);
|
||||
Faction factionHere = getFactionAt(flocationHere);
|
||||
if (factionHere.isNone()) {
|
||||
row += ChatColor.GRAY+"-";
|
||||
} else if (factionHere.isSafeZone()) {
|
||||
row += ChatColor.GOLD+"+";
|
||||
} else {
|
||||
row += factionHere.getRelation(faction).getColor()+"+";
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.add(row);
|
||||
}
|
||||
|
||||
// Get the compass
|
||||
ArrayList<String> asciiCompass = AsciiCompass.getAsciiCompass(inDegrees, ChatColor.RED, Conf.colorChrome);
|
||||
|
||||
// Add the compass
|
||||
ret.set(1, asciiCompass.get(0)+ret.get(1).substring(3*3));
|
||||
ret.set(2, asciiCompass.get(1)+ret.get(2).substring(3*3));
|
||||
ret.set(3, asciiCompass.get(2)+ret.get(3).substring(3*3));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Persistance
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static Map<String,Map<String,Integer>> dumpAsSaveFormat() {
|
||||
Map<String,Map<String,Integer>> worldCoordIds = new HashMap<String,Map<String,Integer>>();
|
||||
|
||||
for (Entry<FLocation, Integer> entry : flocationIds.entrySet()) {
|
||||
String worldName = entry.getKey().getWorldName();
|
||||
String coords = entry.getKey().getCoordString();
|
||||
Integer id = entry.getValue();
|
||||
if ( ! worldCoordIds.containsKey(worldName)) {
|
||||
worldCoordIds.put(worldName, new TreeMap<String,Integer>());
|
||||
}
|
||||
|
||||
worldCoordIds.get(worldName).put(coords, id);
|
||||
}
|
||||
|
||||
return worldCoordIds;
|
||||
}
|
||||
|
||||
public static void loadFromSaveFormat(Map<String,Map<String,Integer>> worldCoordIds) {
|
||||
flocationIds.clear();
|
||||
|
||||
for (Entry<String,Map<String,Integer>> entry : worldCoordIds.entrySet()) {
|
||||
String worldName = entry.getKey();
|
||||
for (Entry<String,Integer> entry2 : entry.getValue().entrySet()) {
|
||||
String[] coords = entry2.getKey().trim().split("[,\\s]+");
|
||||
int x = Integer.parseInt(coords[0]);
|
||||
int z = Integer.parseInt(coords[1]);
|
||||
int factionId = entry2.getValue();
|
||||
flocationIds.put(new FLocation(worldName, x, z), factionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean save() {
|
||||
//Factions.log("Saving board to disk");
|
||||
|
||||
try {
|
||||
DiscUtil.write(file, Factions.gson.toJson(dumpAsSaveFormat()));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to save the board to disk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean load() {
|
||||
Factions.log("Loading board from disk");
|
||||
|
||||
if ( ! file.exists()) {
|
||||
if ( ! loadOld())
|
||||
Factions.log("No board to load from disk. Creating new file.");
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
Type type = new TypeToken<Map<String,Map<String,Integer>>>(){}.getType();
|
||||
Map<String,Map<String,Integer>> worldCoordIds = Factions.gson.fromJson(DiscUtil.read(file), type);
|
||||
loadFromSaveFormat(worldCoordIds);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to load the board from disk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean loadOld() {
|
||||
File folderBoard = new File(Factions.instance.getDataFolder(), "board");
|
||||
|
||||
if ( ! folderBoard.isDirectory())
|
||||
return false;
|
||||
|
||||
Factions.log("Board file doesn't exist, attempting to load old pre-1.1 data.");
|
||||
|
||||
String ext = ".json";
|
||||
|
||||
class jsonFileFilter implements FileFilter {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return (file.getName().toLowerCase().endsWith(".json") && file.isFile());
|
||||
}
|
||||
}
|
||||
|
||||
File[] jsonFiles = folderBoard.listFiles(new jsonFileFilter());
|
||||
for (File jsonFile : jsonFiles) {
|
||||
// Extract the name from the filename. The name is filename minus ".json"
|
||||
String name = jsonFile.getName();
|
||||
name = name.substring(0, name.length() - ext.length());
|
||||
try {
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject json = (JsonObject) parser.parse(DiscUtil.read(jsonFile));
|
||||
JsonArray coords = json.getAsJsonArray("coordFactionIds");
|
||||
Iterator<JsonElement> coordSet = coords.iterator();
|
||||
while(coordSet.hasNext()) {
|
||||
JsonArray coordDat = (JsonArray) coordSet.next();
|
||||
JsonObject coord = coordDat.get(0).getAsJsonObject();
|
||||
int coordX = coord.get("x").getAsInt();
|
||||
int coordZ = coord.get("z").getAsInt();
|
||||
int factionId = coordDat.get(1).getAsInt();
|
||||
flocationIds.put(new FLocation(name, coordX, coordZ), factionId);
|
||||
}
|
||||
Factions.log("loaded pre-1.1 board "+name);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log(Level.WARNING, "failed to load board "+name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
132
src/org/mcteam/factions/Conf.java
Normal file
132
src/org/mcteam/factions/Conf.java
Normal file
@ -0,0 +1,132 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.CreatureType;
|
||||
import org.mcteam.factions.gson.JsonParseException;
|
||||
import org.mcteam.factions.util.DiscUtil;
|
||||
|
||||
|
||||
public class Conf {
|
||||
public static transient File file = new File(Factions.instance.getDataFolder(), "conf.json");
|
||||
|
||||
// Colors
|
||||
public static ChatColor colorMember = ChatColor.GREEN;
|
||||
public static ChatColor colorAlly = ChatColor.LIGHT_PURPLE;
|
||||
public static ChatColor colorNeutral = ChatColor.WHITE;
|
||||
public static ChatColor colorEnemy = ChatColor.RED;
|
||||
|
||||
public static ChatColor colorSystem = ChatColor.YELLOW;
|
||||
public static ChatColor colorChrome = ChatColor.GOLD;
|
||||
public static ChatColor colorCommand = ChatColor.AQUA;
|
||||
public static ChatColor colorParameter = ChatColor.DARK_AQUA;
|
||||
|
||||
// Power
|
||||
public static double powerPlayerMax = 10;
|
||||
public static double powerPlayerMin = -10;
|
||||
public static double powerPerMinute = 0.2; // Default health rate... it takes 5 min to heal one power
|
||||
public static double powerPerDeath = 2; //A death makes you loose 2 power
|
||||
|
||||
public static String prefixAdmin = "**";
|
||||
public static String prefixMod = "*";
|
||||
|
||||
public static int factionTagLengthMin = 3;
|
||||
public static int factionTagLengthMax = 10;
|
||||
public static boolean factionTagForceUpperCase = false;
|
||||
|
||||
// Configuration on the Faction tag in chat messages.
|
||||
|
||||
public static boolean chatTagEnabled = true;
|
||||
public static boolean chatTagRelationColored = true;
|
||||
public static int chatTagInsertIndex = 1;
|
||||
public static String chatTagFormat = "%s"+ChatColor.WHITE+" ";
|
||||
public static String factionChatFormat = "%s"+ChatColor.WHITE+" %s";
|
||||
|
||||
public static boolean allowNoSlashCommand = true;
|
||||
|
||||
public static double autoLeaveAfterDaysOfInactivity = 14;
|
||||
|
||||
public static boolean homesEnabled = true;
|
||||
public static boolean homesTeleportToOnDeath = true;
|
||||
|
||||
public static double territoryShieldFactor = 0.5;
|
||||
public static boolean territoryBlockCreepers = false;
|
||||
public static boolean territoryBlockFireballs = false;
|
||||
public static boolean territoryBlockTNT = false;
|
||||
|
||||
public static boolean safeZoneDenyBuild = true;
|
||||
public static boolean safeZoneDenyUseage = true;
|
||||
public static boolean safeZoneBlockTNT = true;
|
||||
|
||||
public static Set<Material> territoryProtectedMaterials = new HashSet<Material>();
|
||||
public static Set<Material> territoryDenyUseageMaterials = new HashSet<Material>();
|
||||
|
||||
public static transient Set<CreatureType> safeZoneNerfedCreatureTypes = new HashSet<CreatureType>();
|
||||
|
||||
public static transient int mapHeight = 8;
|
||||
public static transient int mapWidth = 49;
|
||||
|
||||
static {
|
||||
territoryProtectedMaterials.add(Material.WOODEN_DOOR);
|
||||
territoryProtectedMaterials.add(Material.DISPENSER);
|
||||
territoryProtectedMaterials.add(Material.CHEST);
|
||||
territoryProtectedMaterials.add(Material.FURNACE);
|
||||
|
||||
territoryDenyUseageMaterials.add(Material.FLINT_AND_STEEL);
|
||||
territoryDenyUseageMaterials.add(Material.BUCKET);
|
||||
territoryDenyUseageMaterials.add(Material.WATER_BUCKET);
|
||||
territoryDenyUseageMaterials.add(Material.LAVA_BUCKET);
|
||||
|
||||
safeZoneNerfedCreatureTypes.add(CreatureType.CREEPER);
|
||||
safeZoneNerfedCreatureTypes.add(CreatureType.GHAST);
|
||||
safeZoneNerfedCreatureTypes.add(CreatureType.PIG_ZOMBIE);
|
||||
safeZoneNerfedCreatureTypes.add(CreatureType.SKELETON);
|
||||
safeZoneNerfedCreatureTypes.add(CreatureType.SPIDER);
|
||||
safeZoneNerfedCreatureTypes.add(CreatureType.SLIME);
|
||||
safeZoneNerfedCreatureTypes.add(CreatureType.ZOMBIE);
|
||||
}
|
||||
|
||||
// track players with admin access who have enabled "admin bypass" mode, and should therefore be able to build anywhere
|
||||
// not worth saving between server restarts, I think
|
||||
public static transient Set<String> adminBypassPlayers = Collections.synchronizedSet(new HashSet<String>());
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Persistance
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean save() {
|
||||
//Factions.log("Saving config to disk.");
|
||||
|
||||
try {
|
||||
DiscUtil.write(file, Factions.gson.toJson(new Conf()));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to save the config to disk.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean load() {
|
||||
Factions.log("Loading conf from disk");
|
||||
|
||||
if ( ! file.exists()) {
|
||||
Factions.log("No conf to load from disk. Creating new file.");
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
Factions.gson.fromJson(DiscUtil.read(file), Conf.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to load the config from disk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
112
src/org/mcteam/factions/FLocation.java
Normal file
112
src/org/mcteam/factions/FLocation.java
Normal file
@ -0,0 +1,112 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class FLocation {
|
||||
|
||||
private String worldName = "world";
|
||||
private int x = 0;
|
||||
private int z = 0;
|
||||
|
||||
private final static transient double cellSize = 16;
|
||||
|
||||
//----------------------------------------------//
|
||||
// Constructors
|
||||
//----------------------------------------------//
|
||||
|
||||
public FLocation() {
|
||||
|
||||
}
|
||||
|
||||
public FLocation(String worldName, int x, int z) {
|
||||
this.worldName = worldName;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public FLocation(Location location) {
|
||||
this(location.getWorld().getName(), (int) Math.floor(location.getX() / cellSize) , (int) Math.floor(location.getZ() / cellSize));
|
||||
}
|
||||
|
||||
public FLocation(Player player) {
|
||||
this(player.getLocation());
|
||||
}
|
||||
|
||||
public FLocation(FPlayer fplayer) {
|
||||
this(fplayer.getPlayer());
|
||||
}
|
||||
|
||||
public FLocation(Block block) {
|
||||
this(block.getLocation());
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Getters and Setters
|
||||
//----------------------------------------------//
|
||||
|
||||
public String getWorldName() {
|
||||
return worldName;
|
||||
}
|
||||
|
||||
public void setWorldName(String worldName) {
|
||||
this.worldName = worldName;
|
||||
}
|
||||
|
||||
public long getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public long getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(int z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public String getCoordString() {
|
||||
return ""+x+","+z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "["+this.getWorldName()+","+this.getCoordString()+"]";
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Misc
|
||||
//----------------------------------------------//
|
||||
|
||||
public FLocation getRelative(int dx, int dz) {
|
||||
return new FLocation(this.worldName, this.x + dx, this.z + dz);
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Comparison
|
||||
//----------------------------------------------//
|
||||
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 19 * hash + (this.worldName != null ? this.worldName.hashCode() : 0);
|
||||
hash = 19 * hash + this.x;
|
||||
hash = 19 * hash + this.z;
|
||||
return hash;
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (!(obj instanceof FLocation))
|
||||
return false;
|
||||
|
||||
FLocation that = (FLocation) obj;
|
||||
return this.x == that.x && this.z == that.z && ( this.worldName==null ? that.worldName==null : this.worldName.equals(that.worldName) );
|
||||
}
|
||||
}
|
558
src/org/mcteam/factions/FPlayer.java
Normal file
558
src/org/mcteam/factions/FPlayer.java
Normal file
@ -0,0 +1,558 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mcteam.factions.gson.reflect.TypeToken;
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
import org.mcteam.factions.util.DiscUtil;
|
||||
|
||||
|
||||
/**
|
||||
* Logged in players always have exactly one FPlayer instance.
|
||||
* Logged out players may or may not have an FPlayer instance. They will always have one if they are part of a faction.
|
||||
* This is because only players with a faction are saved to disk (in order to not waste disk space).
|
||||
*
|
||||
* The FPlayer is linked to a minecraft player using the player name.
|
||||
*
|
||||
* The same instance is always returned for the same player.
|
||||
* This means you can use the == operator. No .equals method necessary.
|
||||
*/
|
||||
|
||||
public class FPlayer {
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Fields
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static transient TreeMap<String, FPlayer> instances = new TreeMap<String, FPlayer>(String.CASE_INSENSITIVE_ORDER);
|
||||
private static transient File file = new File(Factions.instance.getDataFolder(), "players.json");
|
||||
|
||||
private transient String playerName;
|
||||
private transient FLocation lastStoodAt = new FLocation(); // Where did this player stand the last time we checked?
|
||||
|
||||
private int factionId;
|
||||
private Role role;
|
||||
private String title;
|
||||
private double power;
|
||||
private long lastPowerUpdateTime;
|
||||
private long lastLoginTime;
|
||||
private transient boolean mapAutoUpdating;
|
||||
private boolean factionChatting;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Construct
|
||||
// -------------------------------------------- //
|
||||
|
||||
// GSON need this noarg constructor.
|
||||
public FPlayer() {
|
||||
this.resetFactionData();
|
||||
this.power = this.getPowerMax();
|
||||
this.lastPowerUpdateTime = System.currentTimeMillis();
|
||||
this.lastLoginTime = System.currentTimeMillis();
|
||||
this.mapAutoUpdating = false;
|
||||
}
|
||||
|
||||
public void resetFactionData() {
|
||||
this.factionId = 0; // The default neutral faction
|
||||
this.factionChatting = false;
|
||||
this.role = Role.NORMAL;
|
||||
this.title = "";
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Minecraft Player
|
||||
// -------------------------------------------- //
|
||||
|
||||
public Player getPlayer() {
|
||||
return Factions.instance.getServer().getPlayer(playerName);
|
||||
}
|
||||
|
||||
public String getPlayerName() {
|
||||
return this.playerName;
|
||||
}
|
||||
|
||||
public boolean isOnline() {
|
||||
return Factions.instance.getServer().getPlayer(playerName) != null;
|
||||
}
|
||||
|
||||
public boolean isOffline() {
|
||||
return ! isOnline();
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Getters And Setters
|
||||
// -------------------------------------------- //
|
||||
|
||||
public Faction getFaction() {
|
||||
return Faction.get(factionId);
|
||||
}
|
||||
|
||||
private int getFactionId() {
|
||||
return factionId;
|
||||
}
|
||||
|
||||
public void setFaction(Faction faction) {
|
||||
this.factionId = faction.getId();
|
||||
}
|
||||
|
||||
public boolean hasFaction() {
|
||||
return factionId != 0;
|
||||
}
|
||||
|
||||
public Role getRole() {
|
||||
return this.role;
|
||||
}
|
||||
|
||||
public void setRole(Role role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public boolean isFactionChatting() {
|
||||
if (this.factionId == 0) {
|
||||
return false;
|
||||
}
|
||||
return factionChatting;
|
||||
}
|
||||
|
||||
public void setFactionChatting(boolean factionChatting) {
|
||||
this.factionChatting = factionChatting;
|
||||
}
|
||||
|
||||
public long getLastLoginTime() {
|
||||
return lastLoginTime;
|
||||
}
|
||||
|
||||
public void setLastLoginTime(long lastLoginTime) {
|
||||
this.lastLoginTime = lastLoginTime;
|
||||
}
|
||||
|
||||
public boolean isMapAutoUpdating() {
|
||||
return mapAutoUpdating;
|
||||
}
|
||||
|
||||
public void setMapAutoUpdating(boolean mapAutoUpdating) {
|
||||
this.mapAutoUpdating = mapAutoUpdating;
|
||||
}
|
||||
|
||||
public FLocation getLastStoodAt() {
|
||||
return this.lastStoodAt;
|
||||
}
|
||||
|
||||
public void setLastStoodAt(FLocation flocation) {
|
||||
this.lastStoodAt = flocation;
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Title, Name, Faction Tag and Chat
|
||||
//----------------------------------------------//
|
||||
|
||||
// Base:
|
||||
|
||||
public String getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.playerName;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
if ( ! this.hasFaction()) {
|
||||
return "";
|
||||
}
|
||||
return this.getFaction().getTag();
|
||||
}
|
||||
|
||||
// Base concatenations:
|
||||
|
||||
public String getNameAndSomething(String something) {
|
||||
String ret = this.role.getPrefix();
|
||||
if (something.length() > 0) {
|
||||
ret += something+" ";
|
||||
}
|
||||
ret += this.getName();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getNameAndTitle() {
|
||||
return this.getNameAndSomething(this.getTitle());
|
||||
}
|
||||
|
||||
public String getNameAndTag() {
|
||||
return this.getNameAndSomething(this.getTag());
|
||||
}
|
||||
|
||||
// Colored concatenations:
|
||||
// These are used in information messages
|
||||
|
||||
public String getNameAndTitle(Faction faction) {
|
||||
return this.getRelationColor(faction)+this.getNameAndTitle();
|
||||
}
|
||||
public String getNameAndTitle(FPlayer fplayer) {
|
||||
return this.getRelationColor(fplayer)+this.getNameAndTitle();
|
||||
}
|
||||
|
||||
public String getNameAndTag(Faction faction) {
|
||||
return this.getRelationColor(faction)+this.getNameAndTag();
|
||||
}
|
||||
public String getNameAndTag(FPlayer fplayer) {
|
||||
return this.getRelationColor(fplayer)+this.getNameAndTag();
|
||||
}
|
||||
|
||||
public String getNameAndRelevant(Faction faction) {
|
||||
// Which relation?
|
||||
Relation rel = this.getRelation(faction);
|
||||
|
||||
// For member we show title
|
||||
if (rel == Relation.MEMBER) {
|
||||
return rel.getColor() + this.getNameAndTitle();
|
||||
}
|
||||
|
||||
// For non members we show tag
|
||||
return rel.getColor() + this.getNameAndTag();
|
||||
}
|
||||
public String getNameAndRelevant(FPlayer fplayer) {
|
||||
return getNameAndRelevant(fplayer.getFaction());
|
||||
}
|
||||
|
||||
// Chat Tag:
|
||||
// These are injected into the format of global chat messages.
|
||||
|
||||
public String getChatTag() {
|
||||
if ( ! this.hasFaction()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return String.format(Conf.chatTagFormat, this.role.getPrefix()+this.getTag());
|
||||
}
|
||||
|
||||
// Colored Chat Tag
|
||||
public String getChatTag(Faction faction) {
|
||||
if ( ! this.hasFaction()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return this.getRelation(faction).getColor()+getChatTag();
|
||||
}
|
||||
public String getChatTag(FPlayer fplayer) {
|
||||
if ( ! this.hasFaction()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return this.getRelation(fplayer).getColor()+getChatTag();
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Relation and relation colors
|
||||
// -------------------------------
|
||||
|
||||
public Relation getRelation(Faction faction) {
|
||||
return faction.getRelation(this);
|
||||
}
|
||||
|
||||
public Relation getRelation(FPlayer fplayer) {
|
||||
return this.getFaction().getRelation(fplayer);
|
||||
}
|
||||
|
||||
public ChatColor getRelationColor(Faction faction) {
|
||||
return faction.getRelationColor(this);
|
||||
}
|
||||
|
||||
public ChatColor getRelationColor(FPlayer fplayer) {
|
||||
return this.getRelation(fplayer).getColor();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------//
|
||||
// Health
|
||||
//----------------------------------------------//
|
||||
public void heal(int amnt) {
|
||||
Player player = this.getPlayer();
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
player.setHealth(player.getHealth() + amnt);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------//
|
||||
// Power
|
||||
//----------------------------------------------//
|
||||
public double getPower() {
|
||||
this.updatePower();
|
||||
return this.power;
|
||||
}
|
||||
|
||||
protected void alterPower(double delta) {
|
||||
this.power += delta;
|
||||
if (this.power > this.getPowerMax()) {
|
||||
this.power = this.getPowerMax();
|
||||
} else if (this.power < this.getPowerMin()) {
|
||||
this.power = this.getPowerMin();
|
||||
}
|
||||
//Log.debug("Power of "+this.getName()+" is now: "+this.power);
|
||||
}
|
||||
|
||||
public double getPowerMax() {
|
||||
return Conf.powerPlayerMax;
|
||||
}
|
||||
|
||||
public double getPowerMin() {
|
||||
return Conf.powerPlayerMin;
|
||||
}
|
||||
|
||||
public int getPowerRounded() {
|
||||
return (int) Math.round(this.getPower());
|
||||
}
|
||||
|
||||
public int getPowerMaxRounded() {
|
||||
return (int) Math.round(this.getPowerMax());
|
||||
}
|
||||
|
||||
public int getPowerMinRounded() {
|
||||
return (int) Math.round(this.getPowerMin());
|
||||
}
|
||||
|
||||
protected void updatePower() {
|
||||
long now = System.currentTimeMillis();
|
||||
long millisPassed = now - this.lastPowerUpdateTime;
|
||||
this.lastPowerUpdateTime = now;
|
||||
|
||||
int millisPerMinute = 60*1000;
|
||||
this.alterPower(millisPassed * Conf.powerPerMinute / millisPerMinute);
|
||||
}
|
||||
|
||||
public void onDeath() {
|
||||
this.updatePower();
|
||||
this.alterPower(-Conf.powerPerDeath);
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Territory
|
||||
//----------------------------------------------//
|
||||
public boolean isInOwnTerritory() {
|
||||
return Board.getFactionAt(new FLocation(this)) == this.getFaction();
|
||||
}
|
||||
|
||||
public boolean isInOthersTerritory() {
|
||||
int idHere = Board.getIdAt(new FLocation(this));
|
||||
return idHere != 0 && idHere != this.factionId;
|
||||
}
|
||||
|
||||
public void sendFactionHereMessage() {
|
||||
Faction factionHere = Board.getFactionAt(new FLocation(this));
|
||||
String msg = Conf.colorSystem+" ~ "+factionHere.getTag(this);
|
||||
if (factionHere.getDescription().length() > 0) {
|
||||
msg += " - "+factionHere.getDescription();
|
||||
}
|
||||
this.sendMessage(msg);
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Actions
|
||||
// -------------------------------
|
||||
|
||||
public void leave() {
|
||||
Faction myFaction = this.getFaction();
|
||||
|
||||
if (this.getRole() == Role.ADMIN && myFaction.getFPlayers().size() > 1) {
|
||||
sendMessage("You must give the admin role to someone else first.");
|
||||
return;
|
||||
}
|
||||
|
||||
myFaction.sendMessage(this.getNameAndRelevant(myFaction) + Conf.colorSystem + " left your faction.");
|
||||
this.resetFactionData();
|
||||
|
||||
if (myFaction.getFPlayers().size() == 0) {
|
||||
// Remove this faction
|
||||
for (FPlayer fplayer : FPlayer.getAllOnline()) {
|
||||
fplayer.sendMessage("The faction "+myFaction.getTag(fplayer)+Conf.colorSystem+" was disbanded.");
|
||||
}
|
||||
Faction.delete(myFaction.getId());
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Messages
|
||||
// -------------------------------------------- //
|
||||
public void sendMessage(String message) {
|
||||
if (this.getPlayer() != null)
|
||||
this.getPlayer().sendMessage(Conf.colorSystem + message);
|
||||
}
|
||||
|
||||
public void sendMessage(List<String> messages) {
|
||||
for(String message : messages) {
|
||||
this.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Get and search
|
||||
// -------------------------------------------- //
|
||||
|
||||
// You should use this one to be sure you do not spell the player name wrong.
|
||||
public static FPlayer get(Player player) {
|
||||
return get(player.getName());
|
||||
}
|
||||
|
||||
private static FPlayer get(String playerName) {
|
||||
if (instances.containsKey(playerName)) {
|
||||
return instances.get(playerName);
|
||||
}
|
||||
|
||||
FPlayer vplayer = new FPlayer();
|
||||
vplayer.playerName = playerName;
|
||||
|
||||
instances.put(playerName, vplayer);
|
||||
return vplayer;
|
||||
}
|
||||
|
||||
public static Set<FPlayer> getAllOnline() {
|
||||
Set<FPlayer> fplayers = new HashSet<FPlayer>();
|
||||
for (Player player : Factions.instance.getServer().getOnlinePlayers()) {
|
||||
fplayers.add(FPlayer.get(player));
|
||||
}
|
||||
return fplayers;
|
||||
}
|
||||
|
||||
public static Collection<FPlayer> getAll() {
|
||||
return instances.values();
|
||||
}
|
||||
|
||||
public static FPlayer find(String playername) {
|
||||
for (Entry<String, FPlayer> entry : instances.entrySet()) {
|
||||
if (entry.getKey().equalsIgnoreCase(playername)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Persistance
|
||||
// -------------------------------------------- //
|
||||
|
||||
public boolean shouldBeSaved() {
|
||||
return this.factionId != 0;
|
||||
}
|
||||
|
||||
public static boolean save() {
|
||||
//Factions.log("Saving players to disk");
|
||||
|
||||
// We only wan't to save the players with non default values
|
||||
Map<String, FPlayer> playersToSave = new HashMap<String, FPlayer>();
|
||||
for (Entry<String, FPlayer> entry : instances.entrySet()) {
|
||||
if (entry.getValue().shouldBeSaved()) {
|
||||
playersToSave.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
DiscUtil.write(file, Factions.gson.toJson(playersToSave));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to save the players to disk.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean load() {
|
||||
Factions.log("Loading players from disk");
|
||||
if ( ! file.exists()) {
|
||||
if ( ! loadOld())
|
||||
Factions.log("No players to load from disk. Creating new file.");
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
Type type = new TypeToken<Map<String, FPlayer>>(){}.getType();
|
||||
Map<String, FPlayer> instancesFromFile = Factions.gson.fromJson(DiscUtil.read(file), type);
|
||||
instances.clear();
|
||||
instances.putAll(instancesFromFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to load the players from disk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
fillPlayernames();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void fillPlayernames() {
|
||||
for(Entry<String, FPlayer> entry : instances.entrySet()) {
|
||||
entry.getValue().playerName = entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
public static void clean() {
|
||||
for (FPlayer fplayer : instances.values()) {
|
||||
if ( ! Faction.exists(fplayer.getFactionId())) {
|
||||
Factions.log("Reset faction data (invalid faction) for player "+fplayer.getName());
|
||||
fplayer.resetFactionData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void autoLeaveOnInactivityRoutine() {
|
||||
long now = System.currentTimeMillis();
|
||||
double toleranceMillis = Conf.autoLeaveAfterDaysOfInactivity * 24 * 60 * 60 * 1000;
|
||||
|
||||
for (FPlayer fplayer : FPlayer.getAll()) {
|
||||
if (now - fplayer.getLastLoginTime() > toleranceMillis) {
|
||||
fplayer.leave();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean loadOld() {
|
||||
File folderFollower = new File(Factions.instance.getDataFolder(), "follower");
|
||||
|
||||
if ( ! folderFollower.isDirectory())
|
||||
return false;
|
||||
|
||||
Factions.log("Players file doesn't exist, attempting to load old pre-1.1 data.");
|
||||
|
||||
String ext = ".json";
|
||||
|
||||
class jsonFileFilter implements FileFilter {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return (file.getName().toLowerCase().endsWith(".json") && file.isFile());
|
||||
}
|
||||
}
|
||||
|
||||
File[] jsonFiles = folderFollower.listFiles(new jsonFileFilter());
|
||||
|
||||
for (File jsonFile : jsonFiles) {
|
||||
// Extract the name from the filename. The name is filename minus ".json"
|
||||
String name = jsonFile.getName();
|
||||
name = name.substring(0, name.length() - ext.length());
|
||||
try {
|
||||
FPlayer follower = Factions.gson.fromJson(DiscUtil.read(jsonFile), FPlayer.class);
|
||||
follower.playerName = name;
|
||||
follower.lastLoginTime = System.currentTimeMillis();
|
||||
instances.put(follower.playerName, follower);
|
||||
Factions.log("loaded pre-1.1 follower "+name);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log(Level.WARNING, "failed to load follower "+name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
483
src/org/mcteam/factions/Faction.java
Normal file
483
src/org/mcteam/factions/Faction.java
Normal file
@ -0,0 +1,483 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mcteam.factions.gson.reflect.TypeToken;
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
import org.mcteam.factions.util.*;
|
||||
|
||||
|
||||
public class Faction {
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Fields
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static transient Map<Integer, Faction> instances = new HashMap<Integer, Faction>();
|
||||
private static transient File file = new File(Factions.instance.getDataFolder(), "factions.json");
|
||||
private static transient int nextId;
|
||||
|
||||
private transient int id;
|
||||
private Map<Integer, Relation> relationWish;
|
||||
private Set<String> invites; // Where string is a lowercase player name
|
||||
private boolean open;
|
||||
private String tag;
|
||||
private String description;
|
||||
private Location home;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Construct
|
||||
// -------------------------------------------- //
|
||||
|
||||
public Faction() {
|
||||
this.relationWish = new HashMap<Integer, Relation>();
|
||||
this.invites = new HashSet<String>();
|
||||
this.open = true;
|
||||
this.tag = "???";
|
||||
this.description = "Default faction description :(";
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Getters And Setters
|
||||
// -------------------------------------------- //
|
||||
|
||||
public int getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public boolean getOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
public void setOpen(boolean isOpen) {
|
||||
open = isOpen;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return this.getTag("");
|
||||
}
|
||||
public String getTag(String prefix) {
|
||||
return prefix+this.tag;
|
||||
}
|
||||
public String getTag(Faction otherFaction) {
|
||||
return this.getTag(otherFaction.getRelationColor(this).toString());
|
||||
}
|
||||
public String getTag(FPlayer otherFplayer) {
|
||||
return this.getTag(otherFplayer.getRelationColor(this).toString());
|
||||
}
|
||||
public void setTag(String str) {
|
||||
if (Conf.factionTagForceUpperCase) {
|
||||
str = str.toUpperCase();
|
||||
}
|
||||
this.tag = str;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
public void setDescription(String value) {
|
||||
this.description = value;
|
||||
}
|
||||
|
||||
public void setHome(Location home) {
|
||||
this.home = home;
|
||||
}
|
||||
|
||||
public Location getHome() {
|
||||
return home;
|
||||
}
|
||||
|
||||
public boolean hasHome() {
|
||||
return this.home != null;
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Understand the types
|
||||
// -------------------------------
|
||||
|
||||
public boolean isNormal() {
|
||||
return this.getId() > 0;
|
||||
}
|
||||
|
||||
public boolean isNone() {
|
||||
return this.getId() == 0;
|
||||
}
|
||||
|
||||
public boolean isSafeZone() {
|
||||
return this.getId() == -1;
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Invites - uses lowercase name
|
||||
// -------------------------------
|
||||
|
||||
public void invite(FPlayer fplayer) {
|
||||
this.invites.add(fplayer.getName().toLowerCase());
|
||||
}
|
||||
|
||||
public void deinvite(FPlayer fplayer) {
|
||||
this.invites.remove(fplayer.getName().toLowerCase());
|
||||
}
|
||||
|
||||
public boolean isInvited(FPlayer fplayer) {
|
||||
return this.invites.contains(fplayer.getName().toLowerCase());
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Relation and relation colors TODO
|
||||
// -------------------------------
|
||||
|
||||
public Relation getRelationWish(Faction otherFaction) {
|
||||
if (this.relationWish.containsKey(otherFaction.getId())){
|
||||
return this.relationWish.get(otherFaction.getId());
|
||||
}
|
||||
return Relation.NEUTRAL;
|
||||
}
|
||||
|
||||
public void setRelationWish(Faction otherFaction, Relation relation) {
|
||||
if (this.relationWish.containsKey(otherFaction.getId()) && relation.equals(Relation.NEUTRAL)){
|
||||
this.relationWish.remove(otherFaction.getId());
|
||||
} else {
|
||||
this.relationWish.put(otherFaction.getId(), relation);
|
||||
}
|
||||
}
|
||||
|
||||
public Relation getRelation(Faction otherFaction) {
|
||||
if (otherFaction.isNone() || this.isNone()) {
|
||||
return Relation.NEUTRAL;
|
||||
}
|
||||
if (otherFaction.equals(this)) {
|
||||
return Relation.MEMBER;
|
||||
}
|
||||
if(this.getRelationWish(otherFaction).value >= otherFaction.getRelationWish(this).value) {
|
||||
return otherFaction.getRelationWish(this);
|
||||
}
|
||||
return this.getRelationWish(otherFaction);
|
||||
}
|
||||
|
||||
public Relation getRelation(FPlayer fplayer) {
|
||||
return getRelation(fplayer.getFaction());
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Power
|
||||
//----------------------------------------------//
|
||||
public double getPower() {
|
||||
double ret = 0;
|
||||
for (FPlayer fplayer : this.getFPlayers()) {
|
||||
ret += fplayer.getPower();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public double getPowerMax() {
|
||||
double ret = 0;
|
||||
for (FPlayer fplayer : this.getFPlayers()) {
|
||||
ret += fplayer.getPowerMax();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int getPowerRounded() {
|
||||
return (int) Math.round(this.getPower());
|
||||
}
|
||||
|
||||
public int getPowerMaxRounded() {
|
||||
return (int) Math.round(this.getPowerMax());
|
||||
}
|
||||
|
||||
public int getLandRounded() {
|
||||
return Board.getFactionCoordCount(this);
|
||||
}
|
||||
|
||||
public boolean hasLandInflation() {
|
||||
return this.getLandRounded() > this.getPowerRounded();
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Fplayers
|
||||
// -------------------------------
|
||||
|
||||
public ArrayList<FPlayer> getFPlayers() {
|
||||
ArrayList<FPlayer> ret = new ArrayList<FPlayer>();
|
||||
for (FPlayer fplayer : FPlayer.getAll()) {
|
||||
if (fplayer.getFaction() == this) {
|
||||
ret.add(fplayer);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ArrayList<FPlayer> getFPlayersWhereOnline(boolean online) {
|
||||
ArrayList<FPlayer> ret = new ArrayList<FPlayer>();
|
||||
for (FPlayer fplayer : FPlayer.getAll()) {
|
||||
if (fplayer.getFaction() == this && fplayer.isOnline() == online) {
|
||||
ret.add(fplayer);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ArrayList<FPlayer> getFPlayersWhereRole(Role role) {
|
||||
ArrayList<FPlayer> ret = new ArrayList<FPlayer>();
|
||||
|
||||
for (FPlayer fplayer : FPlayer.getAll()) {
|
||||
if (fplayer.getFaction() == this && fplayer.getRole() == role) {
|
||||
ret.add(fplayer);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ArrayList<Player> getOnlinePlayers() {
|
||||
ArrayList<Player> ret = new ArrayList<Player>();
|
||||
for (Player player: Factions.instance.getServer().getOnlinePlayers()) {
|
||||
FPlayer fplayer = FPlayer.get(player);
|
||||
if (fplayer.getFaction() == this) {
|
||||
ret.add(player);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Faction tag
|
||||
//----------------------------------------------//
|
||||
|
||||
public String getComparisonTag() {
|
||||
return TextUtil.getComparisonString(this.tag);
|
||||
}
|
||||
|
||||
public static ArrayList<String> validateTag(String str) {
|
||||
ArrayList<String> errors = new ArrayList<String>();
|
||||
|
||||
if(TextUtil.getComparisonString(str).length() < Conf.factionTagLengthMin) {
|
||||
errors.add(Conf.colorSystem+"The faction tag can't be shorter than "+Conf.factionTagLengthMin+ " chars.");
|
||||
}
|
||||
|
||||
if(str.length() > Conf.factionTagLengthMax) {
|
||||
errors.add(Conf.colorSystem+"The faction tag can't be longer than "+Conf.factionTagLengthMax+ " chars.");
|
||||
}
|
||||
|
||||
for (char c : str.toCharArray()) {
|
||||
if ( ! TextUtil.substanceChars.contains(String.valueOf(c))) {
|
||||
errors.add(Conf.colorSystem+"Faction tag must be alphanumeric. \""+c+"\" is not allowed.");
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
public static Faction findByTag(String str) {
|
||||
String compStr = TextUtil.getComparisonString(str);
|
||||
for (Faction faction : Faction.getAll()) {
|
||||
if (faction.getComparisonTag().equals(compStr)) {
|
||||
return faction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isTagTaken(String str) {
|
||||
return Faction.findByTag(str) != null;
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Messages
|
||||
//----------------------------------------------//
|
||||
public void sendMessage(String message) {
|
||||
for (FPlayer fplayer : this.getFPlayersWhereOnline(true)) {
|
||||
fplayer.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(List<String> messages) {
|
||||
for (FPlayer fplayer : this.getFPlayersWhereOnline(true)) {
|
||||
fplayer.sendMessage(messages);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Mudd TODO
|
||||
//----------------------------------------------//
|
||||
|
||||
public ChatColor getRelationColor(Faction otherFaction) {
|
||||
return this.getRelation(otherFaction).getColor();
|
||||
}
|
||||
|
||||
public ChatColor getRelationColor(FPlayer fplayer) {
|
||||
return this.getRelation(fplayer).getColor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------//
|
||||
// Persistance and entity management
|
||||
//----------------------------------------------//
|
||||
|
||||
public static boolean save() {
|
||||
//Factions.log("Saving factions to disk");
|
||||
|
||||
try {
|
||||
DiscUtil.write(file, Factions.gson.toJson(instances));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to save the factions to disk due to I/O exception.");
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to save the factions to disk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean load() {
|
||||
Factions.log("Loading factions from disk");
|
||||
|
||||
if ( ! file.exists()) {
|
||||
if ( ! loadOld())
|
||||
Factions.log("No factions to load from disk. Creating new file.");
|
||||
save();
|
||||
}
|
||||
|
||||
try {
|
||||
Type type = new TypeToken<Map<Integer, Faction>>(){}.getType();
|
||||
Map<Integer, Faction> instancesFromFile = Factions.gson.fromJson(DiscUtil.read(file), type);
|
||||
instances.clear();
|
||||
instances.putAll(instancesFromFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log("Failed to load the factions from disk.");
|
||||
return false;
|
||||
}
|
||||
|
||||
fillIds();
|
||||
|
||||
// Make sure the default neutral faction exists
|
||||
if ( ! instances.containsKey(0)) {
|
||||
Faction faction = new Faction();
|
||||
faction.tag = "*No faction*";
|
||||
faction.description = "\"The faction for the factionless :P\"";
|
||||
faction.id = 0;
|
||||
instances.put(faction.id, faction);
|
||||
}
|
||||
|
||||
// Make sure the safe zone faciton exists
|
||||
if ( ! instances.containsKey(-1)) {
|
||||
Faction faction = new Faction();
|
||||
faction.tag = ChatColor.GOLD+"Safe Zone";
|
||||
faction.description = "Free from PVP and monsters";
|
||||
faction.id = -1;
|
||||
instances.put(faction.id, faction);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void fillIds() {
|
||||
nextId = 1;
|
||||
for(Entry<Integer, Faction> entry : instances.entrySet()) {
|
||||
entry.getValue().id = entry.getKey();
|
||||
if (nextId < entry.getKey()) {
|
||||
nextId = entry.getKey();
|
||||
}
|
||||
}
|
||||
nextId += 1; // make it the next id and not the current highest.
|
||||
}
|
||||
|
||||
public static Faction get(Integer factionId) {
|
||||
if ( ! instances.containsKey(factionId)) {
|
||||
Factions.log(Level.WARNING, "Non existing factionId "+factionId+" requested! Issuing cleaning!");
|
||||
Board.clean();
|
||||
FPlayer.clean();
|
||||
}
|
||||
return instances.get(factionId);
|
||||
}
|
||||
|
||||
public static Faction getNone() {
|
||||
return instances.get(0);
|
||||
}
|
||||
|
||||
public static Faction getSafeZone() {
|
||||
return instances.get(-1);
|
||||
}
|
||||
|
||||
public static boolean exists(Integer factionId) {
|
||||
return instances.containsKey(factionId);
|
||||
}
|
||||
|
||||
public static Collection<Faction> getAll() {
|
||||
return instances.values();
|
||||
}
|
||||
|
||||
//TODO ta parametrar här. All info som behövs ska matas in här och så sparar vi i denna method.
|
||||
public static Faction create() {
|
||||
Faction faction = new Faction();
|
||||
faction.id = nextId;
|
||||
nextId += 1;
|
||||
instances.put(faction.id, faction);
|
||||
Factions.log("created new faction "+faction.id);
|
||||
//faction.save();
|
||||
return faction;
|
||||
}
|
||||
|
||||
public static void delete(Integer id) {
|
||||
// Remove the faction
|
||||
instances.remove(id);
|
||||
|
||||
// Clean the board
|
||||
Board.clean();
|
||||
|
||||
// Clean the fplayers
|
||||
FPlayer.clean();
|
||||
}
|
||||
|
||||
private static boolean loadOld() {
|
||||
File folderFaction = new File(Factions.instance.getDataFolder(), "faction");
|
||||
|
||||
if ( ! folderFaction.isDirectory())
|
||||
return false;
|
||||
|
||||
Factions.log("Factions file doesn't exist, attempting to load old pre-1.1 data.");
|
||||
|
||||
String ext = ".json";
|
||||
|
||||
class jsonFileFilter implements FileFilter {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
return (file.getName().toLowerCase().endsWith(".json") && file.isFile());
|
||||
}
|
||||
}
|
||||
|
||||
File[] jsonFiles = folderFaction.listFiles(new jsonFileFilter());
|
||||
for (File jsonFile : jsonFiles) {
|
||||
// Extract the name from the filename. The name is filename minus ".json"
|
||||
String name = jsonFile.getName();
|
||||
name = name.substring(0, name.length() - ext.length());
|
||||
int id = Integer.parseInt(name);
|
||||
|
||||
try {
|
||||
Faction faction = Factions.gson.fromJson(DiscUtil.read(jsonFile), Faction.class);
|
||||
faction.id = id;
|
||||
instances.put(faction.id, faction);
|
||||
Factions.log("loaded pre-1.1 faction "+id);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Factions.log(Level.WARNING, "Failed to load faction "+id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
305
src/org/mcteam/factions/Factions.java
Normal file
305
src/org/mcteam/factions/Factions.java
Normal file
@ -0,0 +1,305 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.mcteam.factions.commands.FBaseCommand;
|
||||
import org.mcteam.factions.commands.FCommandAdmin;
|
||||
import org.mcteam.factions.commands.FCommandBypass;
|
||||
import org.mcteam.factions.commands.FCommandChat;
|
||||
import org.mcteam.factions.commands.FCommandClaim;
|
||||
import org.mcteam.factions.commands.FCommandCreate;
|
||||
import org.mcteam.factions.commands.FCommandDeinvite;
|
||||
import org.mcteam.factions.commands.FCommandDescription;
|
||||
import org.mcteam.factions.commands.FCommandHelp;
|
||||
import org.mcteam.factions.commands.FCommandHome;
|
||||
import org.mcteam.factions.commands.FCommandInvite;
|
||||
import org.mcteam.factions.commands.FCommandJoin;
|
||||
import org.mcteam.factions.commands.FCommandKick;
|
||||
import org.mcteam.factions.commands.FCommandLeave;
|
||||
import org.mcteam.factions.commands.FCommandList;
|
||||
import org.mcteam.factions.commands.FCommandMap;
|
||||
import org.mcteam.factions.commands.FCommandMod;
|
||||
import org.mcteam.factions.commands.FCommandOpen;
|
||||
import org.mcteam.factions.commands.FCommandRelationAlly;
|
||||
import org.mcteam.factions.commands.FCommandRelationEnemy;
|
||||
import org.mcteam.factions.commands.FCommandRelationNeutral;
|
||||
import org.mcteam.factions.commands.FCommandSafeclaim;
|
||||
import org.mcteam.factions.commands.FCommandSethome;
|
||||
import org.mcteam.factions.commands.FCommandShow;
|
||||
import org.mcteam.factions.commands.FCommandTag;
|
||||
import org.mcteam.factions.commands.FCommandTitle;
|
||||
import org.mcteam.factions.commands.FCommandUnclaim;
|
||||
import org.mcteam.factions.commands.FCommandVersion;
|
||||
import org.mcteam.factions.gson.Gson;
|
||||
import org.mcteam.factions.gson.GsonBuilder;
|
||||
import org.mcteam.factions.listeners.FactionsBlockListener;
|
||||
import org.mcteam.factions.listeners.FactionsEntityListener;
|
||||
import org.mcteam.factions.listeners.FactionsPlayerListener;
|
||||
|
||||
|
||||
import com.nijiko.permissions.PermissionHandler;
|
||||
import com.nijikokun.bukkit.Permissions.Permissions;
|
||||
|
||||
import me.taylorkelly.help.Help;
|
||||
|
||||
/**
|
||||
* The data is saved to disk every 30min and on plugin disable.
|
||||
*/
|
||||
public class Factions extends JavaPlugin {
|
||||
// -------------------------------------------- //
|
||||
// Fields
|
||||
// -------------------------------------------- //
|
||||
public static Factions instance;
|
||||
private Integer saveTask = null;
|
||||
|
||||
public final static Gson gson = new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.VOLATILE)
|
||||
.registerTypeAdapter(Location.class, new MyLocationTypeAdapter())
|
||||
.create();
|
||||
|
||||
private final FactionsPlayerListener playerListener = new FactionsPlayerListener();
|
||||
private final FactionsEntityListener entityListener = new FactionsEntityListener();
|
||||
private final FactionsBlockListener blockListener = new FactionsBlockListener();
|
||||
|
||||
public static PermissionHandler Permissions;
|
||||
public static Help helpPlugin;
|
||||
|
||||
// Commands
|
||||
public List<FBaseCommand> commands = new ArrayList<FBaseCommand>();
|
||||
|
||||
private String baseCommand;
|
||||
|
||||
public Factions() {
|
||||
Factions.instance = this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
log("=== INIT START ===");
|
||||
long timeInitStart = System.currentTimeMillis();
|
||||
|
||||
// Add the commands
|
||||
commands.add(new FCommandHelp());
|
||||
commands.add(new FCommandAdmin());
|
||||
commands.add(new FCommandBypass());
|
||||
commands.add(new FCommandChat());
|
||||
commands.add(new FCommandClaim());
|
||||
commands.add(new FCommandCreate());
|
||||
commands.add(new FCommandDeinvite());
|
||||
commands.add(new FCommandDescription());
|
||||
commands.add(new FCommandHome());
|
||||
commands.add(new FCommandInvite());
|
||||
commands.add(new FCommandJoin());
|
||||
commands.add(new FCommandKick());
|
||||
commands.add(new FCommandLeave());
|
||||
commands.add(new FCommandList());
|
||||
commands.add(new FCommandMap());
|
||||
commands.add(new FCommandMod());
|
||||
commands.add(new FCommandOpen());
|
||||
commands.add(new FCommandRelationAlly());
|
||||
commands.add(new FCommandRelationEnemy());
|
||||
commands.add(new FCommandRelationNeutral());
|
||||
commands.add(new FCommandSafeclaim());
|
||||
commands.add(new FCommandSethome());
|
||||
commands.add(new FCommandShow());
|
||||
commands.add(new FCommandTag());
|
||||
commands.add(new FCommandTitle());
|
||||
commands.add(new FCommandUnclaim());
|
||||
commands.add(new FCommandVersion());
|
||||
|
||||
// Ensure basefolder exists!
|
||||
this.getDataFolder().mkdirs();
|
||||
|
||||
Conf.load();
|
||||
FPlayer.load();
|
||||
Faction.load();
|
||||
Board.load();
|
||||
|
||||
setupHelp();
|
||||
setupPermissions();
|
||||
|
||||
// Register events
|
||||
PluginManager pm = this.getServer().getPluginManager();
|
||||
pm.registerEvent(Event.Type.PLAYER_CHAT, this.playerListener, Event.Priority.Highest, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_INTERACT, this.playerListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_MOVE, this.playerListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_JOIN, this.playerListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_RESPAWN, this.playerListener, Event.Priority.High, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_BUCKET_EMPTY, this.playerListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.PLAYER_BUCKET_FILL, this.playerListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.ENTITY_DEATH, this.entityListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.ENTITY_DAMAGE, this.entityListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.ENTITY_EXPLODE, this.entityListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.CREATURE_SPAWN, this.entityListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.ENTITY_TARGET, this.entityListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.BLOCK_BREAK, this.blockListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.BLOCK_DAMAGE, this.blockListener, Event.Priority.Normal, this);
|
||||
pm.registerEvent(Event.Type.BLOCK_PLACE, this.blockListener, Event.Priority.Normal, this);
|
||||
|
||||
// Register recurring tasks
|
||||
long saveTicks = 20 * 60 * 30; // Approximately every 30 min
|
||||
if (saveTask == null)
|
||||
saveTask = this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new SaveTask(), saveTicks, saveTicks);
|
||||
|
||||
log("=== INIT DONE (Took "+(System.currentTimeMillis()-timeInitStart)+"ms) ===");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (saveTask != null) {
|
||||
this.getServer().getScheduler().cancelTask(saveTask);
|
||||
saveTask = null;
|
||||
}
|
||||
saveAll();
|
||||
log("Disabled");
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Integration with other plugins
|
||||
// -------------------------------------------- //
|
||||
|
||||
private void setupHelp() {
|
||||
if (helpPlugin != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin test = this.getServer().getPluginManager().getPlugin("Help");
|
||||
|
||||
if (test != null) {
|
||||
helpPlugin = ((Help) test);
|
||||
Factions.log("Found and will use plugin "+helpPlugin.getDescription().getFullName());
|
||||
helpPlugin.registerCommand(this.getBaseCommand()+" help *[page]", "Factions plugin help.", this, false);
|
||||
helpPlugin.registerCommand("help factions", "instead use: /f help", helpPlugin, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPermissions() {
|
||||
if (Permissions != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin test = this.getServer().getPluginManager().getPlugin("Permissions");
|
||||
|
||||
if (test != null) {
|
||||
Permissions = ((Permissions)test).getHandler();
|
||||
Factions.log("Found and will use plugin "+((Permissions)test).getDescription().getFullName());
|
||||
} else {
|
||||
Factions.log("Permission system not detected, defaulting to OP");
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Test rights
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean hasPermParticipate(CommandSender sender) {
|
||||
return hasPerm(sender, "factions.participate", false);
|
||||
}
|
||||
|
||||
public static boolean hasPermCreate(CommandSender sender) {
|
||||
return hasPerm(sender, "factions.create", false);
|
||||
}
|
||||
|
||||
public static boolean hasPermManageSafeZone(CommandSender sender) {
|
||||
return hasPerm(sender, "factions.manageSafeZone", true);
|
||||
}
|
||||
|
||||
public static boolean hasPermAdminBypass(CommandSender sender) {
|
||||
return hasPerm(sender, "factions.adminBypass", true);
|
||||
}
|
||||
|
||||
private static boolean hasPerm(CommandSender sender, String permNode, boolean fallbackOnlyOp) {
|
||||
if (Factions.Permissions == null || ! (sender instanceof Player)) {
|
||||
return fallbackOnlyOp == false || sender.isOp();
|
||||
}
|
||||
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player)sender;
|
||||
return Factions.Permissions.has(player, permNode);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Commands
|
||||
// -------------------------------------------- //
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public String getBaseCommand() {
|
||||
if (this.baseCommand != null) {
|
||||
return this.baseCommand;
|
||||
}
|
||||
|
||||
Map<String, Object> Commands = (Map<String, Object>)this.getDescription().getCommands();
|
||||
this.baseCommand = Commands.keySet().iterator().next();
|
||||
return this.baseCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
||||
List<String> parameters = new ArrayList<String>(Arrays.asList(args));
|
||||
this.handleCommand(sender, parameters);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void handleCommand(CommandSender sender, List<String> parameters) {
|
||||
if (parameters.size() == 0) {
|
||||
this.commands.get(0).execute(sender, parameters);
|
||||
return;
|
||||
}
|
||||
|
||||
String commandName = parameters.get(0).toLowerCase();
|
||||
parameters.remove(0);
|
||||
|
||||
for (FBaseCommand fcommand : this.commands) {
|
||||
if (fcommand.getAliases().contains(commandName)) {
|
||||
fcommand.execute(sender, parameters);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(Conf.colorSystem+"Unknown faction command \""+commandName+"\". Try "+Conf.colorCommand+"/f help");
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Logging
|
||||
// -------------------------------------------- //
|
||||
public static void log(String msg) {
|
||||
log(Level.INFO, msg);
|
||||
}
|
||||
|
||||
public static void log(Level level, String msg) {
|
||||
Logger.getLogger("Minecraft").log(level, "["+instance.getDescription().getFullName()+"] "+msg);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Save all
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static void saveAll() {
|
||||
FPlayer.save();
|
||||
Faction.save();
|
||||
Board.save();
|
||||
Conf.save();
|
||||
}
|
||||
|
||||
}
|
78
src/org/mcteam/factions/MyLocationTypeAdapter.java
Normal file
78
src/org/mcteam/factions/MyLocationTypeAdapter.java
Normal file
@ -0,0 +1,78 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.mcteam.factions.gson.JsonDeserializationContext;
|
||||
import org.mcteam.factions.gson.JsonDeserializer;
|
||||
import org.mcteam.factions.gson.JsonElement;
|
||||
import org.mcteam.factions.gson.JsonObject;
|
||||
import org.mcteam.factions.gson.JsonParseException;
|
||||
import org.mcteam.factions.gson.JsonSerializationContext;
|
||||
import org.mcteam.factions.gson.JsonSerializer;
|
||||
|
||||
|
||||
public class MyLocationTypeAdapter implements JsonDeserializer<Location>, JsonSerializer<Location> {
|
||||
private static final String WORLD = "world";
|
||||
private static final String X = "x";
|
||||
private static final String Y = "y";
|
||||
private static final String Z = "z";
|
||||
private static final String YAW = "yaw";
|
||||
private static final String PITCH = "pitch";
|
||||
|
||||
@Override
|
||||
public Location deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
try {
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
|
||||
String worldname = obj.get(WORLD).getAsString();
|
||||
World world = Factions.instance.getServer().getWorld(worldname);
|
||||
if (world == null) {
|
||||
Factions.log(Level.WARNING, "Stored location's world \"" + worldname + "\" not found on server; dropping the location.");
|
||||
return null;
|
||||
}
|
||||
|
||||
double x = obj.get(X).getAsDouble();
|
||||
double y = obj.get(Y).getAsDouble();
|
||||
double z = obj.get(Z).getAsDouble();
|
||||
float yaw = obj.get(YAW).getAsFloat();
|
||||
float pitch = obj.get(PITCH).getAsFloat();
|
||||
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
Factions.log(Level.WARNING, "Error encountered while deserializing a location.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Location src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject obj = new JsonObject();
|
||||
|
||||
try {
|
||||
if (src.getWorld() == null)
|
||||
{
|
||||
Factions.log(Level.WARNING, "Passed location's world was not found on the server. Dropping the location.");
|
||||
return obj;
|
||||
}
|
||||
|
||||
obj.addProperty(WORLD, src.getWorld().getName());
|
||||
obj.addProperty(X, src.getX());
|
||||
obj.addProperty(Y, src.getY());
|
||||
obj.addProperty(Z, src.getZ());
|
||||
obj.addProperty(YAW, src.getYaw());
|
||||
obj.addProperty(PITCH, src.getPitch());
|
||||
|
||||
return obj;
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
Factions.log(Level.WARNING, "Error encountered while serializing a location.");
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
12
src/org/mcteam/factions/SaveTask.java
Normal file
12
src/org/mcteam/factions/SaveTask.java
Normal file
@ -0,0 +1,12 @@
|
||||
package org.mcteam.factions;
|
||||
|
||||
public class SaveTask implements Runnable {
|
||||
|
||||
//TODO are they removed on disable?
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Factions.saveAll();
|
||||
}
|
||||
|
||||
}
|
262
src/org/mcteam/factions/commands/FBaseCommand.java
Normal file
262
src/org/mcteam/factions/commands/FBaseCommand.java
Normal file
@ -0,0 +1,262 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.Factions;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
|
||||
public class FBaseCommand {
|
||||
public List<String> aliases;
|
||||
public List<String> requiredParameters;
|
||||
public List<String> optionalParameters;
|
||||
|
||||
public String helpNameAndParams;
|
||||
public String helpDescription;
|
||||
|
||||
public CommandSender sender;
|
||||
public boolean senderMustBePlayer;
|
||||
public Player player;
|
||||
public FPlayer me;
|
||||
|
||||
public List<String> parameters;
|
||||
|
||||
|
||||
public FBaseCommand() {
|
||||
aliases = new ArrayList<String>();
|
||||
requiredParameters = new ArrayList<String>();
|
||||
optionalParameters = new ArrayList<String>();
|
||||
|
||||
senderMustBePlayer = true;
|
||||
|
||||
helpNameAndParams = "fail!";
|
||||
helpDescription = "no description";
|
||||
}
|
||||
|
||||
public List<String> getAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
public void execute(CommandSender sender, List<String> parameters) {
|
||||
this.sender = sender;
|
||||
this.parameters = parameters;
|
||||
|
||||
if ( ! validateCall()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.senderMustBePlayer) {
|
||||
this.player = (Player)sender;
|
||||
this.me = FPlayer.get(this.player);
|
||||
}
|
||||
|
||||
perform();
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
|
||||
}
|
||||
|
||||
public void sendMessage(String message) {
|
||||
sender.sendMessage(Conf.colorSystem+message);
|
||||
}
|
||||
|
||||
public void sendMessage(List<String> messages) {
|
||||
for(String message : messages) {
|
||||
this.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validateCall() {
|
||||
if ( this.senderMustBePlayer && ! (sender instanceof Player)) {
|
||||
sendMessage("This command can only be used by ingame players.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ! hasPermission(sender)) {
|
||||
sendMessage("You lack the permissions to "+this.helpDescription.toLowerCase()+".");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parameters.size() < requiredParameters.size()) {
|
||||
sendMessage("Usage: "+this.getUseageTemplate(true));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return Factions.hasPermParticipate(sender);
|
||||
}
|
||||
|
||||
/*public boolean testPermission(CommandSender sender) {
|
||||
// There are two cases where we default to op:
|
||||
// 1. Permissions is not installed
|
||||
// 2. The sender is not a player
|
||||
if ( Factions.Permissions == null || (! (sender instanceof Player))) {
|
||||
if (this.opOnly && sender.isOp()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// No permissions are needed to use this command.
|
||||
if (this.permissions.length() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = (Player)sender;
|
||||
return Factions.Permissions.has(player, this.permissions);
|
||||
}*/
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Help and usage description
|
||||
// -------------------------------------------- //
|
||||
public String getUseageTemplate(boolean withColor, boolean withDescription) {
|
||||
String ret = "";
|
||||
|
||||
if (withColor) {
|
||||
ret += Conf.colorCommand;
|
||||
}
|
||||
|
||||
ret += Factions.instance.getBaseCommand()+ " " +TextUtil.implode(this.getAliases(), ",")+" ";
|
||||
|
||||
List<String> parts = new ArrayList<String>();
|
||||
|
||||
for (String requiredParameter : this.requiredParameters) {
|
||||
parts.add("["+requiredParameter+"]");
|
||||
}
|
||||
|
||||
for (String optionalParameter : this.optionalParameters) {
|
||||
parts.add("*["+optionalParameter+"]");
|
||||
}
|
||||
|
||||
if (withColor) {
|
||||
ret += Conf.colorParameter;
|
||||
}
|
||||
|
||||
ret += TextUtil.implode(parts, " ");
|
||||
|
||||
if (withDescription) {
|
||||
ret += " "+Conf.colorSystem + this.helpDescription;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getUseageTemplate(boolean withColor) {
|
||||
return getUseageTemplate(withColor, false);
|
||||
}
|
||||
|
||||
public String getUseageTemplate() {
|
||||
return getUseageTemplate(true);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Assertions
|
||||
// -------------------------------------------- //
|
||||
|
||||
public boolean assertHasFaction() {
|
||||
if ( ! me.hasFaction()) {
|
||||
sendMessage("You are not member of any faction.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean assertMinRole(Role role) {
|
||||
if (me.getRole().value < role.value) {
|
||||
sendMessage("You must be "+role+" to "+this.helpDescription+".");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Commonly used logic
|
||||
// -------------------------------------------- //
|
||||
|
||||
public FPlayer findFPlayer(String playerName, boolean defaultToMe) {
|
||||
FPlayer fp = FPlayer.find(playerName);
|
||||
|
||||
if (fp == null) {
|
||||
if (defaultToMe) {
|
||||
return me;
|
||||
}
|
||||
sendMessage("The player \""+playerName+"\" could not be found");
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
public FPlayer findFPlayer(String playerName) {
|
||||
return findFPlayer(playerName, false);
|
||||
}
|
||||
|
||||
|
||||
public Faction findFaction(String factionName, boolean defaultToMine) {
|
||||
// First we search player names
|
||||
FPlayer fp = FPlayer.find(factionName);
|
||||
if (fp != null) {
|
||||
return fp.getFaction();
|
||||
}
|
||||
|
||||
// Secondly we search faction names
|
||||
Faction faction = Faction.findByTag(factionName);
|
||||
if (faction != null) {
|
||||
return faction;
|
||||
}
|
||||
|
||||
if (defaultToMine) {
|
||||
return me.getFaction();
|
||||
}
|
||||
|
||||
me.sendMessage(Conf.colorSystem+"No faction or player \""+factionName+"\" was found");
|
||||
return null;
|
||||
}
|
||||
|
||||
public Faction findFaction(String factionName) {
|
||||
return findFaction(factionName, false);
|
||||
}
|
||||
|
||||
public boolean canIAdministerYou(FPlayer i, FPlayer you) {
|
||||
if ( ! i.getFaction().equals(you.getFaction())) {
|
||||
i.sendMessage(you.getNameAndRelevant(i)+Conf.colorSystem+" is not in the same faction as you.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i.getRole().value > you.getRole().value || i.getRole().equals(Role.ADMIN) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (you.getRole().equals(Role.ADMIN)) {
|
||||
i.sendMessage(Conf.colorSystem+"Only the faction admin can do that.");
|
||||
} else if (i.getRole().equals(Role.MODERATOR)) {
|
||||
i.sendMessage(Conf.colorSystem+"Moderators can't control each other...");
|
||||
} else {
|
||||
i.sendMessage(Conf.colorSystem+"You must be a faction moderator to do that.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean parseBool(String str) {
|
||||
List<String> aliasTrue = new ArrayList<String>();
|
||||
aliasTrue.add("true");
|
||||
aliasTrue.add("yes");
|
||||
aliasTrue.add("y");
|
||||
aliasTrue.add("ok");
|
||||
aliasTrue.add("on");
|
||||
aliasTrue.add("+");
|
||||
|
||||
return aliasTrue.contains(str.toLowerCase());
|
||||
}
|
||||
}
|
60
src/org/mcteam/factions/commands/FCommandAdmin.java
Normal file
60
src/org/mcteam/factions/commands/FCommandAdmin.java
Normal file
@ -0,0 +1,60 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandAdmin extends FBaseCommand {
|
||||
|
||||
public FCommandAdmin() {
|
||||
aliases.add("admin");
|
||||
|
||||
requiredParameters.add("player name");
|
||||
|
||||
helpDescription = "Hand over your admin rights";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.ADMIN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = parameters.get(0);
|
||||
|
||||
FPlayer you = findFPlayer(playerName, false);
|
||||
if (you == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
if (you.getFaction() != myFaction) {
|
||||
sendMessage(you.getNameAndRelevant(me)+Conf.colorSystem+" is not a member in your faction.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (you == me) {
|
||||
sendMessage("The target player musn't be yourself.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
me.setRole(Role.MODERATOR);
|
||||
you.setRole(Role.ADMIN);
|
||||
|
||||
// Inform all players
|
||||
for (FPlayer fplayer : FPlayer.getAllOnline()) {
|
||||
if (fplayer.getFaction() == me.getFaction()) {
|
||||
fplayer.sendMessage(me.getNameAndRelevant(me)+Conf.colorSystem+" gave "+you.getNameAndRelevant(me)+Conf.colorSystem+" the leadership of your faction.");
|
||||
} else {
|
||||
fplayer.sendMessage(me.getNameAndRelevant(fplayer)+Conf.colorSystem+" gave "+you.getNameAndRelevant(fplayer)+Conf.colorSystem+" the leadership of "+myFaction.getTag(fplayer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
33
src/org/mcteam/factions/commands/FCommandBypass.java
Normal file
33
src/org/mcteam/factions/commands/FCommandBypass.java
Normal file
@ -0,0 +1,33 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.bukkit.mcteam.factions.Conf;
|
||||
import com.bukkit.mcteam.factions.Faction;
|
||||
import com.bukkit.mcteam.factions.Factions;
|
||||
import com.bukkit.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandBypass extends FBaseCommand {
|
||||
|
||||
public FCommandBypass() {
|
||||
aliases.add("bypass");
|
||||
|
||||
helpDescription = "Enable admin bypass mode; build/destroy anywhere";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return Factions.hasPermAdminBypass(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() {
|
||||
if ( ! Conf.adminBypassPlayers.contains(player.getName())) {
|
||||
Conf.adminBypassPlayers.add(player.getName());
|
||||
me.sendMessage("You have enabled admin bypass mode. You will be able to build or destroy anywhere.");
|
||||
} else {
|
||||
Conf.adminBypassPlayers.remove(player.getName());
|
||||
me.sendMessage("You have disabled admin bypass mode.");
|
||||
}
|
||||
}
|
||||
}
|
28
src/org/mcteam/factions/commands/FCommandChat.java
Normal file
28
src/org/mcteam/factions/commands/FCommandChat.java
Normal file
@ -0,0 +1,28 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
public class FCommandChat extends FBaseCommand {
|
||||
|
||||
public FCommandChat() {
|
||||
aliases.add("chat");
|
||||
aliases.add("c");
|
||||
|
||||
helpDescription = "Switch faction only chat on and off";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! me.isFactionChatting()) {
|
||||
// Turn on
|
||||
me.setFactionChatting(true);
|
||||
sendMessage("Faction-only chat ENABLED.");
|
||||
} else {
|
||||
// Turn off
|
||||
me.setFactionChatting(false);
|
||||
sendMessage("Faction-only chat DISABLED.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
76
src/org/mcteam/factions/commands/FCommandClaim.java
Normal file
76
src/org/mcteam/factions/commands/FCommandClaim.java
Normal file
@ -0,0 +1,76 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Board;
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FLocation;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandClaim extends FBaseCommand {
|
||||
|
||||
public FCommandClaim() {
|
||||
aliases.add("claim");
|
||||
|
||||
helpDescription = "Claim the land where you are standing";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
FLocation flocation = new FLocation(me);
|
||||
Faction otherFaction = Board.getFactionAt(flocation);
|
||||
|
||||
if (myFaction == otherFaction) {
|
||||
sendMessage("You already own this land.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (myFaction.getLandRounded() >= myFaction.getPowerRounded()) {
|
||||
sendMessage("You can't claim more land! You need more power!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherFaction.getRelation(me) == Relation.ALLY) {
|
||||
sendMessage("You can't claim the land of your allies.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherFaction.isSafeZone()) {
|
||||
sendMessage("You can not claim a SafeZone.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherFaction.isNone()) {
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" claimed some new land :D");
|
||||
} else { //if (otherFaction.isNormal()) {
|
||||
|
||||
if ( ! otherFaction.hasLandInflation()) {
|
||||
// TODO more messages WARN current faction most importantly
|
||||
sendMessage(me.getRelationColor(otherFaction)+otherFaction.getTag()+Conf.colorSystem+" owns this land and is strong enough to keep it.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! Board.isBorderLocation(flocation)) {
|
||||
sendMessage("You must start claiming land at the border of the territory.");
|
||||
return;
|
||||
}
|
||||
|
||||
// ASDF claimed some of your land 450 blocks NNW of you.
|
||||
// ASDf claimed some land from FACTION NAME
|
||||
otherFaction.sendMessage(me.getNameAndRelevant(otherFaction)+Conf.colorSystem+" stole some of your land :O");
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" claimed some land from "+otherFaction.getTag(myFaction));
|
||||
}
|
||||
|
||||
Board.setFactionAt(myFaction, flocation);
|
||||
}
|
||||
|
||||
}
|
59
src/org/mcteam/factions/commands/FCommandCreate.java
Normal file
59
src/org/mcteam/factions/commands/FCommandCreate.java
Normal file
@ -0,0 +1,59 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.Factions;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
|
||||
public class FCommandCreate extends FBaseCommand {
|
||||
|
||||
public FCommandCreate() {
|
||||
aliases.add("create");
|
||||
|
||||
requiredParameters.add("faction tag");
|
||||
|
||||
helpDescription = "Create a new faction";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return Factions.hasPermCreate(sender);
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
String tag = parameters.get(0);
|
||||
|
||||
if (me.hasFaction()) {
|
||||
sendMessage("You must leave your current faction first.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Faction.isTagTaken(tag)) {
|
||||
sendMessage("That tag is already in use.");
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<String> tagValidationErrors = Faction.validateTag(tag);
|
||||
if (tagValidationErrors.size() > 0) {
|
||||
sendMessage(tagValidationErrors);
|
||||
return;
|
||||
}
|
||||
|
||||
Faction faction = Faction.create();
|
||||
faction.setTag(tag);
|
||||
me.setRole(Role.ADMIN);
|
||||
me.setFaction(faction);
|
||||
|
||||
for (FPlayer follower : FPlayer.getAllOnline()) {
|
||||
follower.sendMessage(me.getNameAndRelevant(follower)+Conf.colorSystem+" created a new faction "+faction.getTag(follower));
|
||||
}
|
||||
|
||||
sendMessage("You should now: " + new FCommandDescription().getUseageTemplate(true, true));
|
||||
}
|
||||
|
||||
}
|
49
src/org/mcteam/factions/commands/FCommandDeinvite.java
Normal file
49
src/org/mcteam/factions/commands/FCommandDeinvite.java
Normal file
@ -0,0 +1,49 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandDeinvite extends FBaseCommand {
|
||||
|
||||
public FCommandDeinvite() {
|
||||
aliases.add("deinvite");
|
||||
aliases.add("deinv");
|
||||
|
||||
requiredParameters.add("player name");
|
||||
|
||||
helpDescription = "Remove a pending invitation";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = parameters.get(0);
|
||||
|
||||
FPlayer you = findFPlayer(playerName, false);
|
||||
if (you == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (you.getFaction() == myFaction) {
|
||||
sendMessage(you.getName()+" is already a member of "+myFaction.getTag());
|
||||
sendMessage("You might want to: " + new FCommandKick().getUseageTemplate());
|
||||
return;
|
||||
}
|
||||
|
||||
myFaction.deinvite(you);
|
||||
|
||||
you.sendMessage(me.getNameAndRelevant(you)+Conf.colorSystem+" revoked your invitation to "+myFaction.getTag(you));
|
||||
myFaction.sendMessage(me.getNameAndRelevant(me)+Conf.colorSystem+" revoked "+you.getNameAndRelevant(me)+"'s"+Conf.colorSystem+" invitation.");
|
||||
}
|
||||
|
||||
}
|
36
src/org/mcteam/factions/commands/FCommandDescription.java
Normal file
36
src/org/mcteam/factions/commands/FCommandDescription.java
Normal file
@ -0,0 +1,36 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
public class FCommandDescription extends FBaseCommand {
|
||||
|
||||
public FCommandDescription() {
|
||||
aliases.add("desc");
|
||||
|
||||
requiredParameters.add("desc");
|
||||
|
||||
helpDescription = "Change the faction description";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
me.getFaction().setDescription(TextUtil.implode(parameters));
|
||||
|
||||
// Broadcast the description to everyone
|
||||
for (FPlayer fplayer : FPlayer.getAllOnline()) {
|
||||
fplayer.sendMessage("The faction "+fplayer.getRelationColor(me)+me.getFaction().getTag()+Conf.colorSystem+" changed their description to:");
|
||||
fplayer.sendMessage(me.getFaction().getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
135
src/org/mcteam/factions/commands/FCommandHelp.java
Normal file
135
src/org/mcteam/factions/commands/FCommandHelp.java
Normal file
@ -0,0 +1,135 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
|
||||
public class FCommandHelp extends FBaseCommand {
|
||||
|
||||
public FCommandHelp() {
|
||||
aliases.add("help");
|
||||
aliases.add("h");
|
||||
aliases.add("?");
|
||||
|
||||
optionalParameters.add("page");
|
||||
|
||||
helpDescription = "Display a help page";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
int page = 1;
|
||||
if (parameters.size() > 0) {
|
||||
try {
|
||||
page = Integer.parseInt(parameters.get(0));
|
||||
} catch (NumberFormatException e) {
|
||||
// wasn't an integer
|
||||
}
|
||||
}
|
||||
sendMessage(TextUtil.titleize("Factions Help ("+page+"/"+helpPages.size()+")"));
|
||||
page -= 1;
|
||||
if (page < 0 || page >= helpPages.size()) {
|
||||
sendMessage("This page does not exist");
|
||||
return;
|
||||
}
|
||||
sendMessage(helpPages.get(page));
|
||||
}
|
||||
|
||||
//----------------------------------------------//
|
||||
// Build the help pages
|
||||
//----------------------------------------------//
|
||||
|
||||
public static ArrayList<ArrayList<String>> helpPages;
|
||||
|
||||
static {
|
||||
helpPages = new ArrayList<ArrayList<String>>();
|
||||
ArrayList<String> pageLines;
|
||||
|
||||
pageLines = new ArrayList<String>();
|
||||
pageLines.add( new FCommandHelp().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandList().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandShow().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandMap().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandJoin().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandLeave().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandChat().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandHome().getUseageTemplate(true, true) );
|
||||
pageLines.add( "Learn how to create a faction on the next page." );
|
||||
helpPages.add(pageLines);
|
||||
|
||||
pageLines = new ArrayList<String>();
|
||||
pageLines.add( "Create a faction using these two commands:" );
|
||||
pageLines.add( new FCommandCreate().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandDescription().getUseageTemplate(true, true) );
|
||||
pageLines.add( "You might wan't to close it and use invitations:" );
|
||||
pageLines.add( new FCommandOpen().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandInvite().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandDeinvite().getUseageTemplate(true, true) );
|
||||
pageLines.add( "And don't forget to set your home:" );
|
||||
pageLines.add( new FCommandSethome().getUseageTemplate(true, true) );
|
||||
helpPages.add(pageLines);
|
||||
|
||||
pageLines = new ArrayList<String>();
|
||||
pageLines.add( "Faction can claim land that will be protected." );
|
||||
pageLines.add( new FCommandClaim().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandUnclaim().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandTag().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandKick().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandMod().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandAdmin().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandTitle().getUseageTemplate(true, true) );
|
||||
pageLines.add( "Player titles are just for fun. No rules connected to them." );
|
||||
helpPages.add(pageLines);
|
||||
|
||||
pageLines = new ArrayList<String>();
|
||||
pageLines.add( new FCommandRelationAlly().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandRelationNeutral().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandRelationEnemy().getUseageTemplate(true, true) );
|
||||
pageLines.add("");
|
||||
pageLines.add("Set the relation you WISH to have with another faction.");
|
||||
pageLines.add("Your default relation with other factions will be neutral.");
|
||||
pageLines.add("");
|
||||
pageLines.add("If BOTH factions choose \"ally\" you will be allies.");
|
||||
pageLines.add("If ONE faction chooses \"enemy\" you will be enemies.");
|
||||
helpPages.add(pageLines);
|
||||
|
||||
pageLines = new ArrayList<String>();
|
||||
pageLines.add("You can never hurt members or allies.");
|
||||
pageLines.add("You can not hurt neutrals in their own territory.");
|
||||
pageLines.add("You can always hurt enemies and players without faction.");
|
||||
pageLines.add("");
|
||||
pageLines.add("Damage from enemies is reduced in your own territory.");
|
||||
pageLines.add("When you die you lose power. It is restored over time.");
|
||||
pageLines.add("The power of a faction is the sum of all member power.");
|
||||
pageLines.add("The power of a faction determines how much land it can hold.");
|
||||
pageLines.add("You can claim land from factions with too little power.");
|
||||
helpPages.add(pageLines);
|
||||
|
||||
pageLines = new ArrayList<String>();
|
||||
pageLines.add("Only faction members can build and destroy in their own");
|
||||
pageLines.add("territory. Usage of the following items is also restricted:");
|
||||
pageLines.add("Door, Chest, Furnace and Dispenser.");
|
||||
pageLines.add("");
|
||||
pageLines.add("Make sure to put pressure plates in front of doors for your");
|
||||
pageLines.add("guest visitors. Otherwise they can't get through. You can");
|
||||
pageLines.add("also use this to create member only areas.");
|
||||
pageLines.add("As dispensers are protected, you can create traps without");
|
||||
pageLines.add("worrying about those arrows getting stolen.");
|
||||
helpPages.add(pageLines);
|
||||
|
||||
pageLines = new ArrayList<String>();
|
||||
pageLines.add("Finally some commands for the server admins:");
|
||||
pageLines.add( new FCommandVersion().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandSafeclaim().getUseageTemplate(true, true) );
|
||||
pageLines.add( new FCommandBypass().getUseageTemplate(true, true) );
|
||||
helpPages.add(pageLines);
|
||||
}
|
||||
|
||||
}
|
||||
|
36
src/org/mcteam/factions/commands/FCommandHome.java
Normal file
36
src/org/mcteam/factions/commands/FCommandHome.java
Normal file
@ -0,0 +1,36 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandHome extends FBaseCommand {
|
||||
|
||||
public FCommandHome() {
|
||||
aliases.add("home");
|
||||
|
||||
helpDescription = "Teleport to the faction home";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! Conf.homesEnabled) {
|
||||
me.sendMessage("Sorry, Faction homes are disabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
if ( ! myFaction.hasHome()) {
|
||||
me.sendMessage("You faction does not have a home. " + (me.getRole().value < Role.MODERATOR.value ? " Ask your leader to:" : "You should:"));
|
||||
me.sendMessage(new FCommandSethome().getUseageTemplate(true, true));
|
||||
return;
|
||||
}
|
||||
|
||||
player.teleport(myFaction.getHome());
|
||||
}
|
||||
|
||||
}
|
49
src/org/mcteam/factions/commands/FCommandInvite.java
Normal file
49
src/org/mcteam/factions/commands/FCommandInvite.java
Normal file
@ -0,0 +1,49 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandInvite extends FBaseCommand {
|
||||
|
||||
public FCommandInvite() {
|
||||
aliases.add("invite");
|
||||
aliases.add("inv");
|
||||
|
||||
requiredParameters.add("player name");
|
||||
|
||||
helpDescription = "Invite a player";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = parameters.get(0);
|
||||
|
||||
FPlayer you = findFPlayer(playerName, false);
|
||||
if (you == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
if (you.getFaction() == myFaction) {
|
||||
sendMessage(you.getName()+" is already a member of "+myFaction.getTag());
|
||||
sendMessage("You might want to: " + new FCommandKick().getUseageTemplate());
|
||||
return;
|
||||
}
|
||||
|
||||
myFaction.invite(you);
|
||||
|
||||
you.sendMessage(me.getNameAndRelevant(you)+Conf.colorSystem+" invited you to "+myFaction.getTag(you));
|
||||
myFaction.sendMessage(me.getNameAndRelevant(me)+Conf.colorSystem+" invited "+you.getNameAndRelevant(me)+Conf.colorSystem+" to your faction.");
|
||||
}
|
||||
|
||||
}
|
53
src/org/mcteam/factions/commands/FCommandJoin.java
Normal file
53
src/org/mcteam/factions/commands/FCommandJoin.java
Normal file
@ -0,0 +1,53 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.Faction;
|
||||
|
||||
public class FCommandJoin extends FBaseCommand {
|
||||
|
||||
public FCommandJoin() {
|
||||
aliases.add("join");
|
||||
|
||||
requiredParameters.add("faction name");
|
||||
|
||||
helpDescription = "Join a faction";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
String factionName = parameters.get(0);
|
||||
|
||||
Faction faction = findFaction(factionName);
|
||||
if (faction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! faction.isNormal()) {
|
||||
sendMessage("You may only join normal factions. This is a system faction.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (faction == me.getFaction()) {
|
||||
sendMessage("You are already a member of "+faction.getTag(me));
|
||||
return;
|
||||
}
|
||||
|
||||
if (me.hasFaction()) {
|
||||
sendMessage("You must leave your current faction first.");
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! faction.getOpen() && ! faction.isInvited(me)) {
|
||||
sendMessage("This guild requires invitation.");
|
||||
faction.sendMessage(me.getNameAndRelevant(faction)+Conf.colorSystem+" tried to join your faction.");
|
||||
return;
|
||||
}
|
||||
|
||||
me.sendMessage(Conf.colorSystem+"You successfully joined "+faction.getTag(me));
|
||||
faction.sendMessage(me.getNameAndRelevant(faction)+Conf.colorSystem+" joined your faction.");
|
||||
|
||||
me.resetFactionData();
|
||||
me.setFaction(faction);
|
||||
faction.deinvite(me);
|
||||
}
|
||||
|
||||
}
|
50
src/org/mcteam/factions/commands/FCommandKick.java
Normal file
50
src/org/mcteam/factions/commands/FCommandKick.java
Normal file
@ -0,0 +1,50 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
|
||||
public class FCommandKick extends FBaseCommand {
|
||||
|
||||
public FCommandKick() {
|
||||
aliases.add("kick");
|
||||
|
||||
requiredParameters.add("player name");
|
||||
|
||||
helpDescription = "Kick a player from the faction";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
String playerName = parameters.get(0);
|
||||
|
||||
FPlayer you = findFPlayer(playerName, false);
|
||||
if (you == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
if (you.getFaction() != myFaction) {
|
||||
sendMessage(you.getNameAndRelevant(me)+Conf.colorSystem+" is not a member of "+myFaction.getTag(me));
|
||||
return;
|
||||
}
|
||||
|
||||
if (me == you) {
|
||||
sendMessage("You cannot kick yourself.");
|
||||
sendMessage("You might want to: " + new FCommandLeave().getUseageTemplate());
|
||||
return;
|
||||
}
|
||||
|
||||
if (you.getRole().value >= me.getRole().value) { // TODO add more informative messages.
|
||||
sendMessage("Your rank is too low to kick this player.");
|
||||
return;
|
||||
}
|
||||
|
||||
myFaction.deinvite(you);
|
||||
you.resetFactionData();
|
||||
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" kicked "+you.getNameAndRelevant(myFaction)+Conf.colorSystem+" from the faction! :O");
|
||||
you.sendMessage(me.getNameAndRelevant(you)+Conf.colorSystem+" kicked you from "+myFaction.getTag(you)+Conf.colorSystem+"! :O");
|
||||
}
|
||||
|
||||
}
|
26
src/org/mcteam/factions/commands/FCommandLeave.java
Normal file
26
src/org/mcteam/factions/commands/FCommandLeave.java
Normal file
@ -0,0 +1,26 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class FCommandLeave extends FBaseCommand {
|
||||
|
||||
public FCommandLeave() {
|
||||
aliases.add("leave");
|
||||
|
||||
helpDescription = "Leave your faction";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
me.leave();
|
||||
}
|
||||
|
||||
}
|
92
src/org/mcteam/factions/commands/FCommandList.java
Normal file
92
src/org/mcteam/factions/commands/FCommandList.java
Normal file
@ -0,0 +1,92 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
|
||||
public class FCommandList extends FBaseCommand {
|
||||
|
||||
public FCommandList() {
|
||||
aliases.add("list");
|
||||
aliases.add("ls");
|
||||
|
||||
optionalParameters.add("page");
|
||||
|
||||
helpDescription = "Show a list of the factions";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
ArrayList<Faction> FactionList = new ArrayList<Faction>(Faction.getAll());
|
||||
FactionList.remove(Faction.getNone());
|
||||
FactionList.remove(Faction.getSafeZone());
|
||||
|
||||
int page = 1;
|
||||
if (parameters.size() > 0) {
|
||||
try {
|
||||
page = Integer.parseInt(parameters.get(0));
|
||||
} catch (NumberFormatException e) {
|
||||
// wasn't an integer
|
||||
}
|
||||
}
|
||||
page -= 1;
|
||||
|
||||
// Sort by total followers first
|
||||
Collections.sort(FactionList, new Comparator<Faction>(){
|
||||
@Override
|
||||
public int compare(Faction f1, Faction f2) {
|
||||
if (f1.getFPlayers().size() < f2.getFPlayers().size())
|
||||
return 1;
|
||||
else if (f1.getFPlayers().size() > f2.getFPlayers().size())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
// Then sort by how many members are online now
|
||||
Collections.sort(FactionList, new Comparator<Faction>(){
|
||||
@Override
|
||||
public int compare(Faction f1, Faction f2) {
|
||||
if (f1.getFPlayersWhereOnline(true).size() < f2.getFPlayersWhereOnline(true).size())
|
||||
return 1;
|
||||
else if (f1.getFPlayersWhereOnline(true).size() > f2.getFPlayersWhereOnline(true).size())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
FactionList.add(0, Faction.getNone());
|
||||
|
||||
int maxPage = (int)Math.floor((double)FactionList.size() / 9D);
|
||||
if (page < 0 || page > maxPage) {
|
||||
sendMessage("The faction list is only " + (maxPage+1) + " page(s) long");
|
||||
return;
|
||||
}
|
||||
|
||||
String header = "Faction List";
|
||||
if (maxPage > 1) header += " (page " + (page+1) + " of " + (maxPage+1) + ")";
|
||||
sendMessage(TextUtil.titleize(header));
|
||||
|
||||
int maxPos = (page+1) * 9;
|
||||
if (maxPos > FactionList.size()) maxPos = FactionList.size();
|
||||
for (int pos = page * 9; pos < maxPos; pos++) {
|
||||
Faction faction = FactionList.get(pos);
|
||||
if (faction.getId() == 0) {
|
||||
sendMessage(faction.getTag(me)+Conf.colorSystem+" "+faction.getFPlayersWhereOnline(true).size() + " online");
|
||||
} else {
|
||||
sendMessage(faction.getTag(me)+Conf.colorSystem+" "+faction.getFPlayersWhereOnline(true).size()+"/"+faction.getFPlayers().size()+" online, "+faction.getLandRounded()+"/"+faction.getPowerRounded()+"/"+faction.getPowerMaxRounded());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
47
src/org/mcteam/factions/commands/FCommandMap.java
Normal file
47
src/org/mcteam/factions/commands/FCommandMap.java
Normal file
@ -0,0 +1,47 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.mcteam.factions.Board;
|
||||
import org.mcteam.factions.FLocation;
|
||||
|
||||
|
||||
public class FCommandMap extends FBaseCommand {
|
||||
|
||||
public FCommandMap() {
|
||||
aliases.add("map");
|
||||
|
||||
optionalParameters.add("on|off");
|
||||
|
||||
helpDescription = "Show territory map, set optional auto update";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if (parameters.size() > 0) {
|
||||
String mapAutoUpdating = parameters.get(0);
|
||||
if (parseBool(mapAutoUpdating)) {
|
||||
// Turn on
|
||||
me.setMapAutoUpdating(true);
|
||||
sendMessage("Map auto update ENABLED.");
|
||||
|
||||
// And show the map once
|
||||
showMap();
|
||||
} else {
|
||||
// Turn off
|
||||
me.setMapAutoUpdating(false);
|
||||
sendMessage("Map auto update DISABLED.");
|
||||
}
|
||||
} else {
|
||||
showMap();
|
||||
}
|
||||
}
|
||||
|
||||
public void showMap() {
|
||||
sendMessage(Board.getMap(me.getFaction(), new FLocation(me), me.getPlayer().getLocation().getYaw()));
|
||||
}
|
||||
|
||||
}
|
57
src/org/mcteam/factions/commands/FCommandMod.java
Normal file
57
src/org/mcteam/factions/commands/FCommandMod.java
Normal file
@ -0,0 +1,57 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandMod extends FBaseCommand {
|
||||
|
||||
public FCommandMod() {
|
||||
aliases.add("mod");
|
||||
|
||||
requiredParameters.add("player name");
|
||||
|
||||
helpDescription = "Give or revoke moderator rights";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.ADMIN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = parameters.get(0);
|
||||
|
||||
FPlayer you = findFPlayer(playerName, false);
|
||||
if (you == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
if (you.getFaction() != myFaction) {
|
||||
sendMessage(you.getNameAndRelevant(me)+Conf.colorSystem+" is not a member in your faction.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (you == me) {
|
||||
sendMessage("The target player musn't be yourself.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (you.getRole() == Role.MODERATOR) {
|
||||
// Revoke
|
||||
you.setRole(Role.NORMAL);
|
||||
myFaction.sendMessage(you.getNameAndRelevant(myFaction)+Conf.colorSystem+" is no longer moderator in your faction.");
|
||||
} else {
|
||||
// Give
|
||||
you.setRole(Role.MODERATOR);
|
||||
myFaction.sendMessage(you.getNameAndRelevant(myFaction)+Conf.colorSystem+" was promoted to moderator in your faction.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
40
src/org/mcteam/factions/commands/FCommandOpen.java
Normal file
40
src/org/mcteam/factions/commands/FCommandOpen.java
Normal file
@ -0,0 +1,40 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandOpen extends FBaseCommand {
|
||||
|
||||
public FCommandOpen() {
|
||||
aliases.add("open");
|
||||
aliases.add("close");
|
||||
|
||||
helpDescription = "Switch if invitation is required to join";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
myFaction.setOpen( ! me.getFaction().getOpen());
|
||||
|
||||
String open = myFaction.getOpen() ? "open" : "closed";
|
||||
|
||||
// Inform
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" changed the faction to "+open);
|
||||
for (Faction faction : Faction.getAll()) {
|
||||
if (faction == me.getFaction()) {
|
||||
continue;
|
||||
}
|
||||
faction.sendMessage(Conf.colorSystem+"The faction "+myFaction.getTag(faction)+Conf.colorSystem+" is now "+open);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
15
src/org/mcteam/factions/commands/FCommandRelationAlly.java
Normal file
15
src/org/mcteam/factions/commands/FCommandRelationAlly.java
Normal file
@ -0,0 +1,15 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
|
||||
public class FCommandRelationAlly extends FRelationCommand {
|
||||
|
||||
public FCommandRelationAlly() {
|
||||
aliases.add("ally");
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
relation(Relation.ALLY, parameters.get(0));
|
||||
}
|
||||
|
||||
}
|
15
src/org/mcteam/factions/commands/FCommandRelationEnemy.java
Normal file
15
src/org/mcteam/factions/commands/FCommandRelationEnemy.java
Normal file
@ -0,0 +1,15 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
|
||||
public class FCommandRelationEnemy extends FRelationCommand {
|
||||
|
||||
public FCommandRelationEnemy() {
|
||||
aliases.add("enemy");
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
relation(Relation.ENEMY, parameters.get(0));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
|
||||
public class FCommandRelationNeutral extends FRelationCommand {
|
||||
|
||||
public FCommandRelationNeutral() {
|
||||
aliases.add("neutral");
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
relation(Relation.NEUTRAL, parameters.get(0));
|
||||
}
|
||||
|
||||
}
|
30
src/org/mcteam/factions/commands/FCommandSafeclaim.java
Normal file
30
src/org/mcteam/factions/commands/FCommandSafeclaim.java
Normal file
@ -0,0 +1,30 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.mcteam.factions.Board;
|
||||
import org.mcteam.factions.FLocation;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.Factions;
|
||||
|
||||
|
||||
public class FCommandSafeclaim extends FBaseCommand {
|
||||
|
||||
public FCommandSafeclaim() {
|
||||
aliases.add("safeclaim");
|
||||
aliases.add("safe");
|
||||
|
||||
helpDescription = "Claim land for the safezone";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return Factions.hasPermManageSafeZone(sender);
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
FLocation flocation = new FLocation(me);
|
||||
Board.setFactionAt(Faction.getSafeZone(), flocation);
|
||||
sendMessage("This land is now a safe zone");
|
||||
}
|
||||
|
||||
}
|
38
src/org/mcteam/factions/commands/FCommandSethome.java
Normal file
38
src/org/mcteam/factions/commands/FCommandSethome.java
Normal file
@ -0,0 +1,38 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandSethome extends FBaseCommand {
|
||||
|
||||
public FCommandSethome() {
|
||||
aliases.add("sethome");
|
||||
|
||||
helpDescription = "Set the faction home";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! Conf.homesEnabled) {
|
||||
me.sendMessage("Sorry, Faction homes are disabled on this server.");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO may only be inside faction territory
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
myFaction.setHome(player.getLocation());
|
||||
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" set the home for your faction. You can now use:");
|
||||
myFaction.sendMessage(new FCommandHome().getUseageTemplate(true, true));
|
||||
}
|
||||
|
||||
}
|
120
src/org/mcteam/factions/commands/FCommandShow.java
Normal file
120
src/org/mcteam/factions/commands/FCommandShow.java
Normal file
@ -0,0 +1,120 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
|
||||
public class FCommandShow extends FBaseCommand {
|
||||
|
||||
public FCommandShow() {
|
||||
aliases.add("show");
|
||||
aliases.add("who");
|
||||
|
||||
optionalParameters.add("faction tag");
|
||||
|
||||
helpDescription = "Show faction information";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
Faction faction;
|
||||
if (parameters.size() > 0) {
|
||||
faction = findFaction(parameters.get(0), true);
|
||||
} else {
|
||||
faction = me.getFaction();
|
||||
}
|
||||
|
||||
Collection<FPlayer> admins = faction.getFPlayersWhereRole(Role.ADMIN);
|
||||
Collection<FPlayer> mods = faction.getFPlayersWhereRole(Role.MODERATOR);
|
||||
Collection<FPlayer> normals = faction.getFPlayersWhereRole(Role.NORMAL);
|
||||
|
||||
sendMessage(TextUtil.titleize(faction.getTag(me)));
|
||||
sendMessage(Conf.colorChrome+"Description: "+Conf.colorSystem+faction.getDescription());
|
||||
if ( ! faction.isNormal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(faction.getOpen()) {
|
||||
sendMessage(Conf.colorChrome+"Joining: "+Conf.colorSystem+"no invitation is needed");
|
||||
} else {
|
||||
sendMessage(Conf.colorChrome+"Joining: "+Conf.colorSystem+"invitation is required");
|
||||
}
|
||||
sendMessage(Conf.colorChrome+"Land / Power / Maxpower: "+Conf.colorSystem+ faction.getLandRounded()+" / "+faction.getPowerRounded()+" / "+faction.getPowerMaxRounded());
|
||||
|
||||
String listpart;
|
||||
|
||||
// List relation
|
||||
String allyList = Conf.colorChrome+"Allies: ";
|
||||
String enemyList = Conf.colorChrome+"Enemies: ";
|
||||
for (Faction otherFaction : Faction.getAll()) {
|
||||
if (otherFaction == faction) {
|
||||
continue;
|
||||
}
|
||||
listpart = otherFaction.getTag(me)+Conf.colorSystem+", ";
|
||||
if (otherFaction.getRelation(faction) == Relation.ALLY) {
|
||||
allyList += listpart;
|
||||
} else if (otherFaction.getRelation(faction) == Relation.ENEMY) {
|
||||
enemyList += listpart;
|
||||
}
|
||||
}
|
||||
if (allyList.endsWith(", ")) {
|
||||
allyList = allyList.substring(0, allyList.length()-2);
|
||||
}
|
||||
if (enemyList.endsWith(", ")) {
|
||||
enemyList = enemyList.substring(0, enemyList.length()-2);
|
||||
}
|
||||
|
||||
sendMessage(allyList);
|
||||
sendMessage(enemyList);
|
||||
|
||||
// List the members...
|
||||
String onlineList = Conf.colorChrome+"Members online: ";
|
||||
String offlineList = Conf.colorChrome+"Members offline: ";
|
||||
for (FPlayer follower : admins) {
|
||||
listpart = follower.getNameAndTitle(me)+Conf.colorSystem+", ";
|
||||
if (follower.isOnline()) {
|
||||
onlineList += listpart;
|
||||
} else {
|
||||
offlineList += listpart;
|
||||
}
|
||||
}
|
||||
for (FPlayer follower : mods) {
|
||||
listpart = follower.getNameAndTitle(me)+Conf.colorSystem+", ";
|
||||
if (follower.isOnline()) {
|
||||
onlineList += listpart;
|
||||
} else {
|
||||
offlineList += listpart;
|
||||
}
|
||||
}
|
||||
for (FPlayer follower : normals) {
|
||||
listpart = follower.getNameAndTitle(me)+Conf.colorSystem+", ";
|
||||
if (follower.isOnline()) {
|
||||
onlineList += listpart;
|
||||
} else {
|
||||
offlineList += listpart;
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineList.endsWith(", ")) {
|
||||
onlineList = onlineList.substring(0, onlineList.length()-2);
|
||||
}
|
||||
if (offlineList.endsWith(", ")) {
|
||||
offlineList = offlineList.substring(0, offlineList.length()-2);
|
||||
}
|
||||
|
||||
sendMessage(onlineList);
|
||||
sendMessage(offlineList);
|
||||
}
|
||||
|
||||
}
|
60
src/org/mcteam/factions/commands/FCommandTag.java
Normal file
60
src/org/mcteam/factions/commands/FCommandTag.java
Normal file
@ -0,0 +1,60 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
|
||||
public class FCommandTag extends FBaseCommand {
|
||||
|
||||
public FCommandTag() {
|
||||
aliases.add("tag");
|
||||
|
||||
requiredParameters.add("faction tag");
|
||||
|
||||
helpDescription = "Change the faction tag";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String tag = parameters.get(0);
|
||||
|
||||
// TODO does not first test cover selfcase?
|
||||
if (Faction.isTagTaken(tag) && ! TextUtil.getComparisonString(tag).equals(me.getFaction().getComparisonTag())) {
|
||||
sendMessage("That tag is already taken");
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<String> errors = new ArrayList<String>();
|
||||
errors.addAll(Faction.validateTag(tag));
|
||||
if (errors.size() > 0) {
|
||||
sendMessage(errors);
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
String oldtag = myFaction.getTag();
|
||||
myFaction.setTag(tag);
|
||||
|
||||
// Inform
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" changed your faction tag to "+Conf.colorMember+myFaction.getTag());
|
||||
for (Faction faction : Faction.getAll()) {
|
||||
if (faction == me.getFaction()) {
|
||||
continue;
|
||||
}
|
||||
faction.sendMessage(Conf.colorSystem+"The faction "+me.getRelationColor(faction)+oldtag+Conf.colorSystem+" chainged their name to "+myFaction.getTag(faction));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
45
src/org/mcteam/factions/commands/FCommandTitle.java
Normal file
45
src/org/mcteam/factions/commands/FCommandTitle.java
Normal file
@ -0,0 +1,45 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FPlayer;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.util.TextUtil;
|
||||
|
||||
public class FCommandTitle extends FBaseCommand {
|
||||
|
||||
public FCommandTitle() {
|
||||
aliases.add("title");
|
||||
|
||||
requiredParameters.add("player name");
|
||||
|
||||
optionalParameters.add("title");
|
||||
|
||||
helpDescription = "Set or remove a players title";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String playerName = parameters.get(0);
|
||||
parameters.remove(0);
|
||||
String title = TextUtil.implode(parameters);
|
||||
|
||||
FPlayer you = findFPlayer(playerName, false);
|
||||
if (you == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! canIAdministerYou(me, you)) {
|
||||
return;
|
||||
}
|
||||
|
||||
you.setTitle(title);
|
||||
|
||||
// Inform
|
||||
Faction myFaction = me.getFaction();
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" changed a title: "+you.getNameAndRelevant(myFaction));
|
||||
}
|
||||
|
||||
}
|
54
src/org/mcteam/factions/commands/FCommandUnclaim.java
Normal file
54
src/org/mcteam/factions/commands/FCommandUnclaim.java
Normal file
@ -0,0 +1,54 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.mcteam.factions.Board;
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.FLocation;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.Factions;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
public class FCommandUnclaim extends FBaseCommand {
|
||||
|
||||
public FCommandUnclaim() {
|
||||
aliases.add("unclaim");
|
||||
aliases.add("declaim");
|
||||
|
||||
helpDescription = "Unclaim the land where you are standing";
|
||||
}
|
||||
|
||||
public void perform() {
|
||||
FLocation flocation = new FLocation(me);
|
||||
Faction otherFaction = Board.getFactionAt(flocation);
|
||||
|
||||
if (otherFaction.isSafeZone()) {
|
||||
if (Factions.hasPermManageSafeZone(sender)) {
|
||||
Board.removeAt(flocation);
|
||||
sendMessage("Safe zone was unclaimed.");
|
||||
} else {
|
||||
sendMessage("This is a safe zone. You lack permissions to unclaim.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
|
||||
|
||||
if ( myFaction != otherFaction) {
|
||||
sendMessage("You don't own this land.");
|
||||
return;
|
||||
}
|
||||
|
||||
Board.removeAt(flocation);
|
||||
|
||||
myFaction.sendMessage(me.getNameAndRelevant(myFaction)+Conf.colorSystem+" unclaimed some land.");
|
||||
}
|
||||
|
||||
}
|
27
src/org/mcteam/factions/commands/FCommandVersion.java
Normal file
27
src/org/mcteam/factions/commands/FCommandVersion.java
Normal file
@ -0,0 +1,27 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.mcteam.factions.Factions;
|
||||
|
||||
|
||||
public class FCommandVersion extends FBaseCommand {
|
||||
|
||||
public FCommandVersion() {
|
||||
aliases.add("version");
|
||||
|
||||
senderMustBePlayer = false;
|
||||
|
||||
helpDescription = "Which version are you using?";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandSender sender) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void perform() {
|
||||
sendMessage("You are running "+Factions.instance.getDescription().getFullName());
|
||||
}
|
||||
|
||||
}
|
56
src/org/mcteam/factions/commands/FRelationCommand.java
Normal file
56
src/org/mcteam/factions/commands/FRelationCommand.java
Normal file
@ -0,0 +1,56 @@
|
||||
package org.mcteam.factions.commands;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.mcteam.factions.Conf;
|
||||
import org.mcteam.factions.Faction;
|
||||
import org.mcteam.factions.Factions;
|
||||
import org.mcteam.factions.struct.Relation;
|
||||
import org.mcteam.factions.struct.Role;
|
||||
|
||||
|
||||
public class FRelationCommand extends FBaseCommand {
|
||||
|
||||
public FRelationCommand() {
|
||||
requiredParameters.add("faction tag");
|
||||
|
||||
helpDescription = "Set relation wish to another faction";
|
||||
}
|
||||
|
||||
public void relation(Relation whishedRelation, String otherFactionName) {
|
||||
if ( ! assertHasFaction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! assertMinRole(Role.MODERATOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Faction myFaction = me.getFaction();
|
||||
Faction otherFaction = findFaction(otherFactionName, false);
|
||||
if (otherFaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherFaction.getId() == 0) {
|
||||
sendMessage("Nope! You can't :) The default faction is not a real faction.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (otherFaction == myFaction) {
|
||||
sendMessage("Nope! You can't declare a relation to yourself :)");
|
||||
return;
|
||||
}
|
||||
|
||||
myFaction.setRelationWish(otherFaction, whishedRelation);
|
||||
Relation currentRelation = myFaction.getRelation(otherFaction);
|
||||
ChatColor currentRelationColor = currentRelation.getColor();
|
||||
if (whishedRelation == currentRelation) {
|
||||
otherFaction.sendMessage(Conf.colorSystem+"Your faction is now "+currentRelationColor+whishedRelation.toString()+Conf.colorSystem+" to "+currentRelationColor+myFaction.getTag());
|
||||
myFaction.sendMessage(Conf.colorSystem+"Your faction is now "+currentRelationColor+whishedRelation.toString()+Conf.colorSystem+" to "+currentRelationColor+otherFaction.getTag());
|
||||
} else {
|
||||
otherFaction.sendMessage(currentRelationColor+myFaction.getTag()+Conf.colorSystem+ " wishes to be your "+whishedRelation.getColor()+whishedRelation.toString());
|
||||
otherFaction.sendMessage(Conf.colorSystem+"Type "+Conf.colorCommand+Factions.instance.getBaseCommand()+" "+whishedRelation+" "+myFaction.getTag()+Conf.colorSystem+" to accept.");
|
||||
myFaction.sendMessage(currentRelationColor+otherFaction.getTag()+Conf.colorSystem+ " were informed that you wish to be "+whishedRelation.getColor()+whishedRelation);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
/**
|
||||
* Strategy for excluding anonymous and local classes.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return isAnonymousOrLocal(f.getDeclaredClass());
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return isAnonymousOrLocal(clazz);
|
||||
}
|
||||
|
||||
private boolean isAnonymousOrLocal(Class<?> clazz) {
|
||||
return !Enum.class.isAssignableFrom(clazz)
|
||||
&& (clazz.isAnonymousClass() || clazz.isLocalClass());
|
||||
}
|
||||
}
|
61
src/org/mcteam/factions/gson/Cache.java
Normal file
61
src/org/mcteam/factions/gson/Cache.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* Defines generic cache interface.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
interface Cache<K, V> {
|
||||
|
||||
/**
|
||||
* Adds the new value object into the cache for the given key. If the key already
|
||||
* exists, then this method will override the value for the key.
|
||||
*
|
||||
* @param key the key identifier for the {@code value} object
|
||||
* @param value the value object to store in the cache
|
||||
*/
|
||||
void addElement(K key, V value);
|
||||
|
||||
/**
|
||||
* Retrieve the cached value for the given {@code key}.
|
||||
*
|
||||
* @param key the key identifying the value
|
||||
* @return the cached value for the given {@code key}
|
||||
*/
|
||||
V getElement(K key);
|
||||
|
||||
/**
|
||||
* Removes the value from the cache for the given key.
|
||||
*
|
||||
* @param key the key identifying the value to remove
|
||||
* @return the value for the given {@code key}
|
||||
*/
|
||||
V removeElement(K key);
|
||||
|
||||
/**
|
||||
* Removes everything from this cache.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @return the number of objects in this cache
|
||||
*/
|
||||
int size();
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Converts the field name that uses camel-case define word separation into separate words that
|
||||
* are separated by the provided {@code separatorString}.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* CamelCaseSeparatorNamingPolicy policy = new CamelCaseSeparatorNamingPolicy("_");
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("integer_Field".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class CamelCaseSeparatorNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
private final String separatorString;
|
||||
|
||||
/**
|
||||
* Constructs a new CamelCaseSeparatorNamingPolicy object that will add the
|
||||
* {@code separatorString} between each of the words separated by camel case.
|
||||
*
|
||||
* @param separatorString the string value to place between words
|
||||
* @throws IllegalArgumentException thrown if the {@code separatorString} parameter
|
||||
* is null or empty.
|
||||
*/
|
||||
public CamelCaseSeparatorNamingPolicy(String separatorString) {
|
||||
Preconditions.checkNotNull(separatorString);
|
||||
Preconditions.checkArgument(!"".equals(separatorString));
|
||||
this.separatorString = separatorString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType,
|
||||
Collection<Annotation> annnotations) {
|
||||
StringBuilder translation = new StringBuilder();
|
||||
for (int i = 0; i < target.length(); i++) {
|
||||
char character = target.charAt(i);
|
||||
if (Character.isUpperCase(character) && translation.length() != 0) {
|
||||
translation.append(separatorString);
|
||||
}
|
||||
translation.append(character);
|
||||
}
|
||||
|
||||
return translation.toString();
|
||||
}
|
||||
}
|
45
src/org/mcteam/factions/gson/CircularReferenceException.java
Normal file
45
src/org/mcteam/factions/gson/CircularReferenceException.java
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* Exception class to indicate a circular reference error.
|
||||
* This class is not part of the public API and hence is not public.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class CircularReferenceException extends RuntimeException {
|
||||
private static final long serialVersionUID = 7444343294106513081L;
|
||||
private final Object offendingNode;
|
||||
|
||||
CircularReferenceException(Object offendingNode) {
|
||||
super("circular reference error");
|
||||
this.offendingNode = offendingNode;
|
||||
}
|
||||
|
||||
public IllegalStateException createDetailedException(FieldAttributes offendingField) {
|
||||
StringBuilder msg = new StringBuilder(getMessage());
|
||||
if (offendingField != null) {
|
||||
msg.append("\n ").append("Offending field: ").append(offendingField.getName() + "\n");
|
||||
}
|
||||
if (offendingNode != null) {
|
||||
msg.append("\n ").append("Offending object: ").append(offendingNode);
|
||||
}
|
||||
return new IllegalStateException(msg.toString(), this);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Performs numerous field naming translations wrapped up as one object.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
abstract class CompositionFieldNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
private final RecursiveFieldNamingPolicy[] fieldPolicies;
|
||||
|
||||
public CompositionFieldNamingPolicy(RecursiveFieldNamingPolicy... fieldNamingPolicies) {
|
||||
if (fieldNamingPolicies == null) {
|
||||
throw new NullPointerException("naming policies can not be null.");
|
||||
}
|
||||
this.fieldPolicies = fieldNamingPolicies;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
||||
for (RecursiveFieldNamingPolicy policy : fieldPolicies) {
|
||||
target = policy.translateName(target, fieldType, annotations);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
}
|
893
src/org/mcteam/factions/gson/DefaultTypeAdapters.java
Normal file
893
src/org/mcteam/factions/gson/DefaultTypeAdapters.java
Normal file
@ -0,0 +1,893 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* List of all the default type adapters ({@link JsonSerializer}s, {@link JsonDeserializer}s,
|
||||
* and {@link InstanceCreator}s.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class DefaultTypeAdapters {
|
||||
|
||||
private static final DefaultDateTypeAdapter DATE_TYPE_ADAPTER = new DefaultDateTypeAdapter();
|
||||
private static final DefaultJavaSqlDateTypeAdapter JAVA_SQL_DATE_TYPE_ADAPTER =
|
||||
new DefaultJavaSqlDateTypeAdapter();
|
||||
private static final DefaultTimeTypeAdapter TIME_TYPE_ADAPTER =
|
||||
new DefaultTimeTypeAdapter();
|
||||
private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER =
|
||||
new DefaultTimestampDeserializer();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter();
|
||||
private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter();
|
||||
private static final UriTypeAdapter URI_TYPE_ADAPTER = new UriTypeAdapter();
|
||||
private static final UuidTypeAdapter UUUID_TYPE_ADAPTER = new UuidTypeAdapter();
|
||||
private static final LocaleTypeAdapter LOCALE_TYPE_ADAPTER = new LocaleTypeAdapter();
|
||||
private static final CollectionTypeAdapter COLLECTION_TYPE_ADAPTER = new CollectionTypeAdapter();
|
||||
private static final MapTypeAdapter MAP_TYPE_ADAPTER = new MapTypeAdapter();
|
||||
private static final BigDecimalTypeAdapter BIG_DECIMAL_TYPE_ADAPTER = new BigDecimalTypeAdapter();
|
||||
private static final BigIntegerTypeAdapter BIG_INTEGER_TYPE_ADAPTER = new BigIntegerTypeAdapter();
|
||||
|
||||
private static final BooleanTypeAdapter BOOLEAN_TYPE_ADAPTER = new BooleanTypeAdapter();
|
||||
private static final ByteTypeAdapter BYTE_TYPE_ADAPTER = new ByteTypeAdapter();
|
||||
private static final CharacterTypeAdapter CHARACTER_TYPE_ADAPTER = new CharacterTypeAdapter();
|
||||
private static final DoubleDeserializer DOUBLE_TYPE_ADAPTER = new DoubleDeserializer();
|
||||
private static final FloatDeserializer FLOAT_TYPE_ADAPTER = new FloatDeserializer();
|
||||
private static final IntegerTypeAdapter INTEGER_TYPE_ADAPTER = new IntegerTypeAdapter();
|
||||
private static final LongDeserializer LONG_DESERIALIZER = new LongDeserializer();
|
||||
private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter();
|
||||
private static final ShortTypeAdapter SHORT_TYPE_ADAPTER = new ShortTypeAdapter();
|
||||
private static final StringTypeAdapter STRING_TYPE_ADAPTER = new StringTypeAdapter();
|
||||
|
||||
private static final PropertiesCreator PROPERTIES_CREATOR = new PropertiesCreator();
|
||||
private static final TreeSetCreator TREE_SET_CREATOR = new TreeSetCreator();
|
||||
private static final HashSetCreator HASH_SET_CREATOR = new HashSetCreator();
|
||||
private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER =
|
||||
new GregorianCalendarTypeAdapter();
|
||||
|
||||
// The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS
|
||||
// must be defined after the constants for the type adapters. Otherwise, the type adapter
|
||||
// constants will appear as nulls.
|
||||
private static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS =
|
||||
createDefaultSerializers();
|
||||
private static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS =
|
||||
createDefaultDeserializers();
|
||||
private static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS =
|
||||
createDefaultInstanceCreators();
|
||||
|
||||
private static ParameterizedTypeHandlerMap<JsonSerializer<?>> createDefaultSerializers() {
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> map =
|
||||
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
||||
|
||||
map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER);
|
||||
map.register(URL.class, URL_TYPE_ADAPTER);
|
||||
map.register(URI.class, URI_TYPE_ADAPTER);
|
||||
map.register(UUID.class, UUUID_TYPE_ADAPTER);
|
||||
map.register(Locale.class, LOCALE_TYPE_ADAPTER);
|
||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
||||
map.register(Date.class, DATE_TYPE_ADAPTER);
|
||||
map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER);
|
||||
map.register(Timestamp.class, DATE_TYPE_ADAPTER);
|
||||
map.register(Time.class, TIME_TYPE_ADAPTER);
|
||||
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
||||
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
||||
map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER);
|
||||
map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER);
|
||||
|
||||
// Add primitive serializers
|
||||
map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER);
|
||||
map.register(boolean.class, BOOLEAN_TYPE_ADAPTER);
|
||||
map.register(Byte.class, BYTE_TYPE_ADAPTER);
|
||||
map.register(byte.class, BYTE_TYPE_ADAPTER);
|
||||
map.register(Character.class, CHARACTER_TYPE_ADAPTER);
|
||||
map.register(char.class, CHARACTER_TYPE_ADAPTER);
|
||||
map.register(Integer.class, INTEGER_TYPE_ADAPTER);
|
||||
map.register(int.class, INTEGER_TYPE_ADAPTER);
|
||||
map.register(Number.class, NUMBER_TYPE_ADAPTER);
|
||||
map.register(Short.class, SHORT_TYPE_ADAPTER);
|
||||
map.register(short.class, SHORT_TYPE_ADAPTER);
|
||||
map.register(String.class, STRING_TYPE_ADAPTER);
|
||||
|
||||
map.makeUnmodifiable();
|
||||
return map;
|
||||
}
|
||||
|
||||
private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultDeserializers() {
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map =
|
||||
new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
||||
map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER));
|
||||
map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER));
|
||||
map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER));
|
||||
map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER));
|
||||
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
|
||||
map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER));
|
||||
map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
|
||||
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
|
||||
map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER));
|
||||
map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER));
|
||||
map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER));
|
||||
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
||||
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
||||
map.register(BigDecimal.class, wrapDeserializer(BIG_DECIMAL_TYPE_ADAPTER));
|
||||
map.register(BigInteger.class, wrapDeserializer(BIG_INTEGER_TYPE_ADAPTER));
|
||||
|
||||
// Add primitive deserializers
|
||||
map.register(Boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
|
||||
map.register(boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
|
||||
map.register(Byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
|
||||
map.register(byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
|
||||
map.register(Character.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
|
||||
map.register(char.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
|
||||
map.register(Double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER));
|
||||
map.register(double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER));
|
||||
map.register(Float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
|
||||
map.register(float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
|
||||
map.register(Integer.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
|
||||
map.register(int.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
|
||||
map.register(Long.class, wrapDeserializer(LONG_DESERIALIZER));
|
||||
map.register(long.class, wrapDeserializer(LONG_DESERIALIZER));
|
||||
map.register(Number.class, wrapDeserializer(NUMBER_TYPE_ADAPTER));
|
||||
map.register(Short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
|
||||
map.register(short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
|
||||
map.register(String.class, wrapDeserializer(STRING_TYPE_ADAPTER));
|
||||
|
||||
map.makeUnmodifiable();
|
||||
return map;
|
||||
}
|
||||
|
||||
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() {
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
||||
new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
||||
|
||||
// Add Collection type instance creators
|
||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
||||
|
||||
map.registerForTypeHierarchy(Set.class, HASH_SET_CREATOR);
|
||||
map.registerForTypeHierarchy(SortedSet.class, TREE_SET_CREATOR);
|
||||
map.register(Properties.class, PROPERTIES_CREATOR);
|
||||
map.makeUnmodifiable();
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static JsonDeserializer<?> wrapDeserializer(JsonDeserializer<?> deserializer) {
|
||||
return new JsonDeserializerExceptionWrapper(deserializer);
|
||||
}
|
||||
|
||||
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers() {
|
||||
return getDefaultSerializers(false, LongSerializationPolicy.DEFAULT);
|
||||
}
|
||||
|
||||
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers(
|
||||
boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) {
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers =
|
||||
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
||||
|
||||
// Double primitive
|
||||
DefaultTypeAdapters.DoubleSerializer doubleSerializer =
|
||||
new DefaultTypeAdapters.DoubleSerializer(serializeSpecialFloatingPointValues);
|
||||
serializers.registerIfAbsent(Double.class, doubleSerializer);
|
||||
serializers.registerIfAbsent(double.class, doubleSerializer);
|
||||
|
||||
// Float primitive
|
||||
DefaultTypeAdapters.FloatSerializer floatSerializer =
|
||||
new DefaultTypeAdapters.FloatSerializer(serializeSpecialFloatingPointValues);
|
||||
serializers.registerIfAbsent(Float.class, floatSerializer);
|
||||
serializers.registerIfAbsent(float.class, floatSerializer);
|
||||
|
||||
// Long primitive
|
||||
DefaultTypeAdapters.LongSerializer longSerializer =
|
||||
new DefaultTypeAdapters.LongSerializer(longSerializationPolicy);
|
||||
serializers.registerIfAbsent(Long.class, longSerializer);
|
||||
serializers.registerIfAbsent(long.class, longSerializer);
|
||||
|
||||
serializers.registerIfAbsent(DEFAULT_SERIALIZERS);
|
||||
return serializers;
|
||||
}
|
||||
|
||||
static ParameterizedTypeHandlerMap<JsonDeserializer<?>> getDefaultDeserializers() {
|
||||
return DEFAULT_DESERIALIZERS;
|
||||
}
|
||||
|
||||
static ParameterizedTypeHandlerMap<InstanceCreator<?>> getDefaultInstanceCreators() {
|
||||
return DEFAULT_INSTANCE_CREATORS;
|
||||
}
|
||||
|
||||
static class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
|
||||
private final DateFormat format;
|
||||
|
||||
DefaultDateTypeAdapter() {
|
||||
this.format = DateFormat.getDateTimeInstance();
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(final String datePattern) {
|
||||
this.format = new SimpleDateFormat(datePattern);
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(final int style) {
|
||||
this.format = DateFormat.getDateInstance(style);
|
||||
}
|
||||
|
||||
public DefaultDateTypeAdapter(final int dateStyle, final int timeStyle) {
|
||||
this.format = DateFormat.getDateTimeInstance(dateStyle, timeStyle);
|
||||
}
|
||||
|
||||
// These methods need to be synchronized since JDK DateFormat classes are not thread-safe
|
||||
// See issue 162
|
||||
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
synchronized (format) {
|
||||
String dateFormatAsString = format.format(src);
|
||||
return new JsonPrimitive(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
|
||||
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
if (!(json instanceof JsonPrimitive)) {
|
||||
throw new JsonParseException("The date should be a string value");
|
||||
}
|
||||
try {
|
||||
synchronized (format) {
|
||||
return format.parse(json.getAsString());
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(DefaultDateTypeAdapter.class.getSimpleName());
|
||||
sb.append('(').append(format.getClass().getSimpleName()).append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>,
|
||||
JsonDeserializer<java.sql.Date> {
|
||||
private final DateFormat format;
|
||||
DefaultJavaSqlDateTypeAdapter() {
|
||||
this.format = new SimpleDateFormat("MMM d, yyyy");
|
||||
}
|
||||
|
||||
public JsonElement serialize(java.sql.Date src, Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
synchronized (format) {
|
||||
String dateFormatAsString = format.format(src);
|
||||
return new JsonPrimitive(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
|
||||
public java.sql.Date deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
if (!(json instanceof JsonPrimitive)) {
|
||||
throw new JsonParseException("The date should be a string value");
|
||||
}
|
||||
try {
|
||||
synchronized (format) {
|
||||
Date date = format.parse(json.getAsString());
|
||||
return new java.sql.Date(date.getTime());
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class DefaultTimestampDeserializer implements JsonDeserializer<Timestamp> {
|
||||
public Timestamp deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
Date date = context.deserialize(json, Date.class);
|
||||
return new Timestamp(date.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
static class DefaultTimeTypeAdapter implements JsonSerializer<Time>, JsonDeserializer<Time> {
|
||||
private final DateFormat format;
|
||||
DefaultTimeTypeAdapter() {
|
||||
this.format = new SimpleDateFormat("hh:mm:ss a");
|
||||
}
|
||||
public JsonElement serialize(Time src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
synchronized (format) {
|
||||
String dateFormatAsString = format.format(src);
|
||||
return new JsonPrimitive(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
public Time deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
if (!(json instanceof JsonPrimitive)) {
|
||||
throw new JsonParseException("The date should be a string value");
|
||||
}
|
||||
try {
|
||||
synchronized (format) {
|
||||
Date date = format.parse(json.getAsString());
|
||||
return new Time(date.getTime());
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class GregorianCalendarTypeAdapter
|
||||
implements JsonSerializer<GregorianCalendar>, JsonDeserializer<GregorianCalendar> {
|
||||
|
||||
private static final String YEAR = "year";
|
||||
private static final String MONTH = "month";
|
||||
private static final String DAY_OF_MONTH = "dayOfMonth";
|
||||
private static final String HOUR_OF_DAY = "hourOfDay";
|
||||
private static final String MINUTE = "minute";
|
||||
private static final String SECOND = "second";
|
||||
|
||||
public JsonElement serialize(GregorianCalendar src, Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty(YEAR, src.get(Calendar.YEAR));
|
||||
obj.addProperty(MONTH, src.get(Calendar.MONTH));
|
||||
obj.addProperty(DAY_OF_MONTH, src.get(Calendar.DAY_OF_MONTH));
|
||||
obj.addProperty(HOUR_OF_DAY, src.get(Calendar.HOUR_OF_DAY));
|
||||
obj.addProperty(MINUTE, src.get(Calendar.MINUTE));
|
||||
obj.addProperty(SECOND, src.get(Calendar.SECOND));
|
||||
return obj;
|
||||
}
|
||||
|
||||
public GregorianCalendar deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObject obj = json.getAsJsonObject();
|
||||
int year = obj.get(YEAR).getAsInt();
|
||||
int month = obj.get(MONTH).getAsInt();
|
||||
int dayOfMonth = obj.get(DAY_OF_MONTH).getAsInt();
|
||||
int hourOfDay = obj.get(HOUR_OF_DAY).getAsInt();
|
||||
int minute = obj.get(MINUTE).getAsInt();
|
||||
int second = obj.get(SECOND).getAsInt();
|
||||
return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return GregorianCalendarTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static class EnumTypeAdapter<T extends Enum<T>>
|
||||
implements JsonSerializer<T>, JsonDeserializer<T> {
|
||||
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.name());
|
||||
}
|
||||
|
||||
@SuppressWarnings("cast")
|
||||
public T deserialize(JsonElement json, Type classOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return (T) Enum.valueOf((Class<T>) classOfT, json.getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return EnumTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class UrlTypeAdapter implements JsonSerializer<URL>, JsonDeserializer<URL> {
|
||||
public JsonElement serialize(URL src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.toExternalForm());
|
||||
}
|
||||
|
||||
public URL deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
try {
|
||||
return new URL(json.getAsString());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return UrlTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class UriTypeAdapter implements JsonSerializer<URI>, JsonDeserializer<URI> {
|
||||
public JsonElement serialize(URI src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.toASCIIString());
|
||||
}
|
||||
public URI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
try {
|
||||
return new URI(json.getAsString());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return UriTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class UuidTypeAdapter implements JsonSerializer<UUID>, JsonDeserializer<UUID> {
|
||||
public JsonElement serialize(UUID src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.toString());
|
||||
}
|
||||
|
||||
public UUID deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return UUID.fromString(json.getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return UuidTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class LocaleTypeAdapter
|
||||
implements JsonSerializer<Locale>, JsonDeserializer<Locale> {
|
||||
public JsonElement serialize(Locale src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.toString());
|
||||
}
|
||||
|
||||
public Locale deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
String locale = json.getAsString();
|
||||
StringTokenizer tokenizer = new StringTokenizer(locale, "_");
|
||||
String language = null;
|
||||
String country = null;
|
||||
String variant = null;
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
language = tokenizer.nextToken();
|
||||
}
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
country = tokenizer.nextToken();
|
||||
}
|
||||
if (tokenizer.hasMoreElements()) {
|
||||
variant = tokenizer.nextToken();
|
||||
}
|
||||
if (country == null && variant == null) {
|
||||
return new Locale(language);
|
||||
} else if (variant == null) {
|
||||
return new Locale(language, country);
|
||||
} else {
|
||||
return new Locale(language, country, variant);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return LocaleTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static class CollectionTypeAdapter implements JsonSerializer<Collection>,
|
||||
JsonDeserializer<Collection>, InstanceCreator<Collection> {
|
||||
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
JsonArray array = new JsonArray();
|
||||
Type childGenericType = null;
|
||||
if (typeOfSrc instanceof ParameterizedType) {
|
||||
childGenericType = new TypeInfoCollection(typeOfSrc).getElementType();
|
||||
}
|
||||
for (Object child : src) {
|
||||
if (child == null) {
|
||||
array.add(JsonNull.createJsonNull());
|
||||
} else {
|
||||
Type childType = (childGenericType == null || childGenericType == Object.class)
|
||||
? child.getClass() : childGenericType;
|
||||
JsonElement element = context.serialize(child, childType);
|
||||
array.add(element);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public Collection deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
if (json.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
|
||||
// This handles cases where users are using their own subclass of Collection.
|
||||
Collection collection = constructCollectionType(typeOfT, context);
|
||||
Type childType = new TypeInfoCollection(typeOfT).getElementType();
|
||||
for (JsonElement childElement : json.getAsJsonArray()) {
|
||||
if (childElement == null || childElement.isJsonNull()) {
|
||||
collection.add(null);
|
||||
} else {
|
||||
Object value = context.deserialize(childElement, childType);
|
||||
collection.add(value);
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
private Collection constructCollectionType(Type collectionType,
|
||||
JsonDeserializationContext context) {
|
||||
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
|
||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
||||
return (Collection) objectConstructor.construct(collectionType);
|
||||
}
|
||||
|
||||
public Collection createInstance(Type type) {
|
||||
return new LinkedList();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PropertiesCreator implements InstanceCreator<Properties> {
|
||||
public Properties createInstance(Type type) {
|
||||
return new Properties();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
static class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>,
|
||||
InstanceCreator<Map> {
|
||||
|
||||
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject map = new JsonObject();
|
||||
Type childGenericType = null;
|
||||
if (typeOfSrc instanceof ParameterizedType) {
|
||||
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
|
||||
}
|
||||
|
||||
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
|
||||
JsonElement valueElement;
|
||||
if (value == null) {
|
||||
valueElement = JsonNull.createJsonNull();
|
||||
} else {
|
||||
Type childType = (childGenericType == null)
|
||||
? value.getClass() : childGenericType;
|
||||
valueElement = context.serialize(value, childType);
|
||||
}
|
||||
map.add(String.valueOf(entry.getKey()), valueElement);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
|
||||
// This handles cases where users are using their own subclass of Map.
|
||||
Map<Object, Object> map = constructMapType(typeOfT, context);
|
||||
TypeInfoMap mapTypeInfo = new TypeInfoMap(typeOfT);
|
||||
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
|
||||
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), mapTypeInfo.getKeyType());
|
||||
Object value = context.deserialize(entry.getValue(), mapTypeInfo.getValueType());
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private Map constructMapType(Type mapType, JsonDeserializationContext context) {
|
||||
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
|
||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
||||
return (Map) objectConstructor.construct(mapType);
|
||||
}
|
||||
|
||||
public Map createInstance(Type type) {
|
||||
return new LinkedHashMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MapTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class BigDecimalTypeAdapter
|
||||
implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> {
|
||||
public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public BigDecimal deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
return json.getAsBigDecimal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return BigDecimalTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class BigIntegerTypeAdapter
|
||||
implements JsonSerializer<BigInteger>, JsonDeserializer<BigInteger> {
|
||||
|
||||
public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public BigInteger deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
return json.getAsBigInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return BigIntegerTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class NumberTypeAdapter
|
||||
implements JsonSerializer<Number>, JsonDeserializer<Number> {
|
||||
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return NumberTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class LongSerializer implements JsonSerializer<Long> {
|
||||
private final LongSerializationPolicy longSerializationPolicy;
|
||||
|
||||
private LongSerializer(LongSerializationPolicy longSerializationPolicy) {
|
||||
this.longSerializationPolicy = longSerializationPolicy;
|
||||
}
|
||||
|
||||
public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return longSerializationPolicy.serialize(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return LongSerializer.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class LongDeserializer implements JsonDeserializer<Long> {
|
||||
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return LongDeserializer.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class IntegerTypeAdapter
|
||||
implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
|
||||
public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return IntegerTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ShortTypeAdapter
|
||||
implements JsonSerializer<Short>, JsonDeserializer<Short> {
|
||||
public JsonElement serialize(Short src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public Short deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ShortTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ByteTypeAdapter implements JsonSerializer<Byte>, JsonDeserializer<Byte> {
|
||||
public JsonElement serialize(Byte src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ByteTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
static class FloatSerializer implements JsonSerializer<Float> {
|
||||
private final boolean serializeSpecialFloatingPointValues;
|
||||
|
||||
FloatSerializer(boolean serializeSpecialDoubleValues) {
|
||||
this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues;
|
||||
}
|
||||
|
||||
public JsonElement serialize(Float src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
if (!serializeSpecialFloatingPointValues) {
|
||||
if (Float.isNaN(src) || Float.isInfinite(src)) {
|
||||
throw new IllegalArgumentException(src
|
||||
+ " is not a valid float value as per JSON specification. To override this"
|
||||
+ " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.");
|
||||
}
|
||||
}
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
}
|
||||
|
||||
private static class FloatDeserializer implements JsonDeserializer<Float> {
|
||||
public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return FloatDeserializer.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
static class DoubleSerializer implements JsonSerializer<Double> {
|
||||
private final boolean serializeSpecialFloatingPointValues;
|
||||
|
||||
DoubleSerializer(boolean serializeSpecialDoubleValues) {
|
||||
this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues;
|
||||
}
|
||||
|
||||
public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
if (!serializeSpecialFloatingPointValues) {
|
||||
if (Double.isNaN(src) || Double.isInfinite(src)) {
|
||||
throw new IllegalArgumentException(src
|
||||
+ " is not a valid double value as per JSON specification. To override this"
|
||||
+ " behavior, use GsonBuilder.serializeSpecialDoubleValues() method.");
|
||||
}
|
||||
}
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DoubleDeserializer implements JsonDeserializer<Double> {
|
||||
public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return DoubleDeserializer.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class CharacterTypeAdapter
|
||||
implements JsonSerializer<Character>, JsonDeserializer<Character> {
|
||||
public JsonElement serialize(Character src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public Character deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsCharacter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return CharacterTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringTypeAdapter
|
||||
implements JsonSerializer<String>, JsonDeserializer<String> {
|
||||
public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class BooleanTypeAdapter
|
||||
implements JsonSerializer<Boolean>, JsonDeserializer<Boolean> {
|
||||
public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return BooleanTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TreeSetCreator implements InstanceCreator<TreeSet<?>> {
|
||||
public TreeSet<?> createInstance(Type type) {
|
||||
return new TreeSet<Object>();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return TreeSetCreator.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
private static class HashSetCreator implements InstanceCreator<HashSet<?>> {
|
||||
public HashSet<?> createInstance(Type type) {
|
||||
return new HashSet<Object>();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return HashSetCreator.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
}
|
117
src/org/mcteam/factions/gson/DelegatingJsonElementVisitor.java
Normal file
117
src/org/mcteam/factions/gson/DelegatingJsonElementVisitor.java
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A simple implementation of the {@link JsonElementVisitor} that simply delegates the method
|
||||
* invocation onto a {@code delegate} instance of the {@link JsonElementVisitor}. This object
|
||||
* can be used to build a chain of visitors such that each Visitor instance can perform some
|
||||
* operation on the {@link JsonElement} and then pass on the input to the delegate. This kind
|
||||
* of pattern is sometimes referred as a "Chain of Responsibility".
|
||||
*
|
||||
* <p>The following is an example use case:
|
||||
*
|
||||
* <pre>
|
||||
* class JsonEscapingVisitor extends DelegatingJsonElementVisitor {
|
||||
* public JsonEscapingVisitor(JsonElementVisitor) {
|
||||
* super(visitor);
|
||||
* }
|
||||
*
|
||||
* public void visitPrimitive(JsonPrimitive primitive) {
|
||||
* JsonPrimitive escapedPrimitive = escapePrimitiveObject(primitive);
|
||||
* super.visitPrimitive(escapedPrimitive);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* JsonElementVisitor visitor = new JsonEscapingVisitor(new FormattingVisitor());
|
||||
* </pre></p>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
class DelegatingJsonElementVisitor implements JsonElementVisitor {
|
||||
private final JsonElementVisitor delegate;
|
||||
|
||||
protected DelegatingJsonElementVisitor(JsonElementVisitor delegate) {
|
||||
Preconditions.checkNotNull(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public void endArray(JsonArray array) throws IOException {
|
||||
delegate.endArray(array);
|
||||
}
|
||||
|
||||
public void endObject(JsonObject object) throws IOException {
|
||||
delegate.endObject(object);
|
||||
}
|
||||
|
||||
public void startArray(JsonArray array) throws IOException {
|
||||
delegate.startArray(array);
|
||||
}
|
||||
|
||||
public void startObject(JsonObject object) throws IOException {
|
||||
delegate.startObject(object);
|
||||
}
|
||||
|
||||
public void visitArrayMember(JsonArray parent, JsonPrimitive member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitArrayMember(parent, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitArrayMember(JsonArray parent, JsonArray member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitArrayMember(parent, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitArrayMember(JsonArray parent, JsonObject member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitArrayMember(parent, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitObjectMember(parent, memberName, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitObjectMember(JsonObject parent, String memberName, JsonArray member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitObjectMember(parent, memberName, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitObjectMember(JsonObject parent, String memberName, JsonObject member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitObjectMember(parent, memberName, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitNullObjectMember(JsonObject parent, String memberName,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitNullObjectMember(parent, memberName, isFirst);
|
||||
}
|
||||
|
||||
public void visitPrimitive(JsonPrimitive primitive) throws IOException {
|
||||
delegate.visitPrimitive(primitive);
|
||||
}
|
||||
|
||||
public void visitNull() throws IOException {
|
||||
delegate.visitNull();
|
||||
}
|
||||
|
||||
public void visitNullArrayMember(JsonArray parent, boolean isFirst) throws IOException {
|
||||
delegate.visitNullArrayMember(parent, isFirst);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A wrapper class used to collect numerous {@link ExclusionStrategy} objects
|
||||
* and perform a short-circuited OR operation.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class DisjunctionExclusionStrategy implements ExclusionStrategy {
|
||||
private final Collection<ExclusionStrategy> strategies;
|
||||
|
||||
public DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) {
|
||||
Preconditions.checkNotNull(strategies);
|
||||
this.strategies = strategies;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
if (strategy.shouldSkipField(f)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
if (strategy.shouldSkipClass(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
160
src/org/mcteam/factions/gson/Escaper.java
Normal file
160
src/org/mcteam/factions/gson/Escaper.java
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A utility class that is used to perform JSON escaping so that ", <, >, etc. characters are
|
||||
* properly encoded in the JSON string representation before returning to the client code.
|
||||
*
|
||||
* <p>This class contains a single method to escape a passed in string value:
|
||||
* <pre>
|
||||
* String jsonStringValue = "beforeQuote\"afterQuote";
|
||||
* String escapedValue = Escaper.escapeJsonString(jsonStringValue);
|
||||
* </pre></p>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class Escaper {
|
||||
|
||||
private static final char[] HEX_CHARS = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
|
||||
private static final Set<Character> JS_ESCAPE_CHARS;
|
||||
private static final Set<Character> HTML_ESCAPE_CHARS;
|
||||
|
||||
static {
|
||||
Set<Character> mandatoryEscapeSet = new HashSet<Character>();
|
||||
mandatoryEscapeSet.add('"');
|
||||
mandatoryEscapeSet.add('\\');
|
||||
JS_ESCAPE_CHARS = Collections.unmodifiableSet(mandatoryEscapeSet);
|
||||
|
||||
Set<Character> htmlEscapeSet = new HashSet<Character>();
|
||||
htmlEscapeSet.add('<');
|
||||
htmlEscapeSet.add('>');
|
||||
htmlEscapeSet.add('&');
|
||||
htmlEscapeSet.add('=');
|
||||
htmlEscapeSet.add('\'');
|
||||
// htmlEscapeSet.add('/'); -- Removing slash for now since it causes some incompatibilities
|
||||
HTML_ESCAPE_CHARS = Collections.unmodifiableSet(htmlEscapeSet);
|
||||
}
|
||||
|
||||
private final boolean escapeHtmlCharacters;
|
||||
|
||||
Escaper(boolean escapeHtmlCharacters) {
|
||||
this.escapeHtmlCharacters = escapeHtmlCharacters;
|
||||
}
|
||||
|
||||
public String escapeJsonString(CharSequence plainText) {
|
||||
StringBuffer escapedString = new StringBuffer(plainText.length() + 20);
|
||||
try {
|
||||
escapeJsonString(plainText, escapedString);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return escapedString.toString();
|
||||
}
|
||||
|
||||
private void escapeJsonString(CharSequence plainText, StringBuffer out) throws IOException {
|
||||
int pos = 0; // Index just past the last char in plainText written to out.
|
||||
int len = plainText.length();
|
||||
|
||||
for (int charCount, i = 0; i < len; i += charCount) {
|
||||
int codePoint = Character.codePointAt(plainText, i);
|
||||
charCount = Character.charCount(codePoint);
|
||||
|
||||
if (!isControlCharacter(codePoint) && !mustEscapeCharInJsString(codePoint)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
out.append(plainText, pos, i);
|
||||
pos = i + charCount;
|
||||
switch (codePoint) {
|
||||
case '\b':
|
||||
out.append("\\b");
|
||||
break;
|
||||
case '\t':
|
||||
out.append("\\t");
|
||||
break;
|
||||
case '\n':
|
||||
out.append("\\n");
|
||||
break;
|
||||
case '\f':
|
||||
out.append("\\f");
|
||||
break;
|
||||
case '\r':
|
||||
out.append("\\r");
|
||||
break;
|
||||
case '\\':
|
||||
out.append("\\\\");
|
||||
break;
|
||||
case '/':
|
||||
out.append("\\/");
|
||||
break;
|
||||
case '"':
|
||||
out.append("\\\"");
|
||||
break;
|
||||
default:
|
||||
appendHexJavaScriptRepresentation(codePoint, out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.append(plainText, pos, len);
|
||||
}
|
||||
|
||||
private boolean mustEscapeCharInJsString(int codepoint) {
|
||||
if (!Character.isSupplementaryCodePoint(codepoint)) {
|
||||
char c = (char) codepoint;
|
||||
return JS_ESCAPE_CHARS.contains(c)
|
||||
|| (escapeHtmlCharacters && HTML_ESCAPE_CHARS.contains(c));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isControlCharacter(int codePoint) {
|
||||
// JSON spec defines these code points as control characters, so they must be escaped
|
||||
return codePoint < 0x20
|
||||
|| codePoint == 0x2028 // Line separator
|
||||
|| codePoint == 0x2029 // Paragraph separator
|
||||
|| (codePoint >= 0x7f && codePoint <= 0x9f);
|
||||
}
|
||||
|
||||
private static void appendHexJavaScriptRepresentation(int codePoint, Appendable out)
|
||||
throws IOException {
|
||||
if (Character.isSupplementaryCodePoint(codePoint)) {
|
||||
// Handle supplementary unicode values which are not representable in
|
||||
// javascript. We deal with these by escaping them as two 4B sequences
|
||||
// so that they will round-trip properly when sent from java to javascript
|
||||
// and back.
|
||||
char[] surrogates = Character.toChars(codePoint);
|
||||
appendHexJavaScriptRepresentation(surrogates[0], out);
|
||||
appendHexJavaScriptRepresentation(surrogates[1], out);
|
||||
return;
|
||||
}
|
||||
out.append("\\u")
|
||||
.append(HEX_CHARS[(codePoint >>> 12) & 0xf])
|
||||
.append(HEX_CHARS[(codePoint >>> 8) & 0xf])
|
||||
.append(HEX_CHARS[(codePoint >>> 4) & 0xf])
|
||||
.append(HEX_CHARS[codePoint & 0xf]);
|
||||
}
|
||||
}
|
95
src/org/mcteam/factions/gson/ExclusionStrategy.java
Normal file
95
src/org/mcteam/factions/gson/ExclusionStrategy.java
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* A strategy (or policy) definition that is used to decide whether or not a field or top-level
|
||||
* class should be serialized or deserialized as part of the JSON output/input. For serialization,
|
||||
* if the {@link #shouldSkipClass(Class)} method returns false then that class or field type
|
||||
* will not be part of the JSON output. For deserialization, if {@link #shouldSkipClass(Class)}
|
||||
* returns false, then it will not be set as part of the Java object structure.
|
||||
*
|
||||
* <p>The following are a few examples that shows how you can use this exclusion mechanism.
|
||||
*
|
||||
* <p><strong>Exclude fields and objects based on a particular class type:</strong>
|
||||
* <pre class="code">
|
||||
* private static class SpecificClassExclusionStrategy implements ExclusionStrategy {
|
||||
* private final Class<?> excludedThisClass;
|
||||
*
|
||||
* public SpecificClassExclusionStrategy(Class<?> excludedThisClass) {
|
||||
* this.excludedThisClass = excludedThisClass;
|
||||
* }
|
||||
*
|
||||
* public boolean shouldSkipClass(Class<?> clazz) {
|
||||
* return excludedThisClass.equals(clazz);
|
||||
* }
|
||||
*
|
||||
* public boolean shouldSkipField(FieldAttributes f) {
|
||||
* return excludedThisClass.equals(f.getDeclaredClass());
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p><strong>Excludes fields and objects based on a particular annotation:</strong>
|
||||
* <pre class="code">
|
||||
* public @interface FooAnnotation {
|
||||
* // some implementation here
|
||||
* }
|
||||
*
|
||||
* // Excludes any field (or class) that is tagged with an "@FooAnnotation"
|
||||
* private static class FooAnnotationExclusionStrategy implements ExclusionStrategy {
|
||||
* public boolean shouldSkipClass(Class<?> clazz) {
|
||||
* return clazz.getAnnotation(FooAnnotation.class) != null;
|
||||
* }
|
||||
*
|
||||
* public boolean shouldSkipField(FieldAttributes f) {
|
||||
* return f.getAnnotation(FooAnnotation.class) != null;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then
|
||||
* the {@code GsonBuilder} is required. The following is an example of how you can use the
|
||||
* {@code GsonBuilder} to configure Gson to use one of the above sample:
|
||||
* <pre class="code">
|
||||
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .setExclusionStrategies(excludeStrings)
|
||||
* .create();
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public interface ExclusionStrategy {
|
||||
|
||||
/**
|
||||
* @param f the field object that is under test
|
||||
* @return true if the field should be ignored; otherwise false
|
||||
*/
|
||||
public boolean shouldSkipField(FieldAttributes f);
|
||||
|
||||
/**
|
||||
* @param clazz the class object that is under test
|
||||
* @return true if the class should be ignored; otherwise false
|
||||
*/
|
||||
public boolean shouldSkipClass(Class<?> clazz);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Excludes fields that do not have the {@link Expose} annotation
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
Expose annotation = f.getAnnotation(Expose.class);
|
||||
if (annotation == null) {
|
||||
return true;
|
||||
}
|
||||
return !annotation.deserialize();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Excludes fields that do not have the {@link Expose} annotation
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
Expose annotation = f.getAnnotation(Expose.class);
|
||||
if (annotation == null) {
|
||||
return true;
|
||||
}
|
||||
return !annotation.serialize();
|
||||
}
|
||||
}
|
229
src/org/mcteam/factions/gson/FieldAttributes.java
Normal file
229
src/org/mcteam/factions/gson/FieldAttributes.java
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* A data object that stores attributes of a field.
|
||||
*
|
||||
* <p>This class is immutable; therefore, it can be safely shared across threads.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public final class FieldAttributes {
|
||||
private static final String MAX_CACHE_PROPERTY_NAME =
|
||||
"com.bukkit.mcteam.gson.annotation_cache_size_hint";
|
||||
|
||||
private static final Cache<Pair<Class<?>, String>, Collection<Annotation>> ANNOTATION_CACHE =
|
||||
new LruCache<Pair<Class<?>,String>, Collection<Annotation>>(getMaxCacheSize());
|
||||
|
||||
private final Class<?> declaringClazz;
|
||||
private final Field field;
|
||||
private final Class<?> declaredType;
|
||||
private final boolean isSynthetic;
|
||||
private final int modifiers;
|
||||
private final String name;
|
||||
|
||||
// Fields used for lazy initialization
|
||||
private Type genericType;
|
||||
private Collection<Annotation> annotations;
|
||||
|
||||
/**
|
||||
* Constructs a Field Attributes object from the {@code f}.
|
||||
*
|
||||
* @param f the field to pull attributes from
|
||||
*/
|
||||
FieldAttributes(final Class<?> declaringClazz, final Field f) {
|
||||
Preconditions.checkNotNull(declaringClazz);
|
||||
this.declaringClazz = declaringClazz;
|
||||
name = f.getName();
|
||||
declaredType = f.getType();
|
||||
isSynthetic = f.isSynthetic();
|
||||
modifiers = f.getModifiers();
|
||||
field = f;
|
||||
}
|
||||
|
||||
private static int getMaxCacheSize() {
|
||||
final int defaultMaxCacheSize = 2000;
|
||||
try {
|
||||
String propertyValue = System.getProperty(
|
||||
MAX_CACHE_PROPERTY_NAME, String.valueOf(defaultMaxCacheSize));
|
||||
return Integer.parseInt(propertyValue);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultMaxCacheSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the declaring class that contains this field
|
||||
*/
|
||||
public Class<?> getDeclaringClass() {
|
||||
return declaringClazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the field
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>For example, assume the following class definition:
|
||||
* <pre class="code">
|
||||
* public class Foo {
|
||||
* private String bar;
|
||||
* private List<String> red;
|
||||
* }
|
||||
*
|
||||
* Type listParmeterizedType = new TypeToken<List<String>>() {}.getType();
|
||||
* </pre>
|
||||
*
|
||||
* <p>This method would return {@code String.class} for the {@code bar} field and
|
||||
* {@code listParameterizedType} for the {@code red} field.
|
||||
*
|
||||
* @return the specific type declared for this field
|
||||
*/
|
||||
public Type getDeclaredType() {
|
||||
if (genericType == null) {
|
||||
genericType = field.getGenericType();
|
||||
}
|
||||
return genericType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Class<?>} object that was declared for this field.
|
||||
*
|
||||
* <p>For example, assume the following class definition:
|
||||
* <pre class="code">
|
||||
* public class Foo {
|
||||
* private String bar;
|
||||
* private List<String> red;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>This method would return {@code String.class} for the {@code bar} field and
|
||||
* {@code List.class} for the {@code red} field.
|
||||
*
|
||||
* @return the specific class object that was declared for the field
|
||||
*/
|
||||
public Class<?> getDeclaredClass() {
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code T} annotation object from this field if it exist; otherwise returns
|
||||
* {@code null}.
|
||||
*
|
||||
* @param annotation the class of the annotation that will be retrieved
|
||||
* @return the annotation instance if it is bound to the field; otherwise {@code null}
|
||||
*/
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotation) {
|
||||
return getAnnotationFromArray(getAnnotations(), annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the annotations that are present on this field.
|
||||
*
|
||||
* @return an array of all the annotations set on the field
|
||||
* @since 1.4
|
||||
*/
|
||||
public Collection<Annotation> getAnnotations() {
|
||||
if (annotations == null) {
|
||||
Pair<Class<?>, String> key = new Pair<Class<?>, String>(declaringClazz, name);
|
||||
annotations = ANNOTATION_CACHE.getElement(key);
|
||||
if (annotations == null) {
|
||||
annotations = Collections.unmodifiableCollection(
|
||||
Arrays.asList(field.getAnnotations()));
|
||||
ANNOTATION_CACHE.addElement(key, annotations);
|
||||
}
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the field is defined with the {@code modifier}.
|
||||
*
|
||||
* <p>This method is meant to be called as:
|
||||
* <pre class="code">
|
||||
* boolean hasPublicModifier = fieldAttribute.hasModifier(java.lang.reflect.Modifier.PUBLIC);
|
||||
* </pre>
|
||||
*
|
||||
* @see java.lang.reflect.Modifier
|
||||
*/
|
||||
public boolean hasModifier(int modifier) {
|
||||
return (modifiers & modifier) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is exposed internally only for the removing synthetic fields from the JSON output.
|
||||
*
|
||||
* @throws IllegalAccessException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
void set(Object instance, Object value) throws IllegalAccessException {
|
||||
field.set(instance, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is exposed internally only for the removing synthetic fields from the JSON output.
|
||||
*
|
||||
* @return true if the field is synthetic; otherwise false
|
||||
* @throws IllegalAccessException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
Object get(Object instance) throws IllegalAccessException {
|
||||
return field.get(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is exposed internally only for the removing synthetic fields from the JSON output.
|
||||
*
|
||||
* @return true if the field is synthetic; otherwise false
|
||||
*/
|
||||
boolean isSynthetic() {
|
||||
return isSynthetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated remove this when {@link FieldNamingStrategy} is deleted.
|
||||
*/
|
||||
@Deprecated
|
||||
Field getFieldObject() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Annotation> T getAnnotationFromArray(
|
||||
Collection<Annotation> annotations, Class<T> annotation) {
|
||||
for (Annotation a : annotations) {
|
||||
if (a.annotationType() == annotation) {
|
||||
return (T) a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
99
src/org/mcteam/factions/gson/FieldNamingPolicy.java
Normal file
99
src/org/mcteam/factions/gson/FieldNamingPolicy.java
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* An enumeration that defines a few standard naming conventions for JSON field names.
|
||||
* This enumeration should be used in conjunction with {@link org.mcteam.factions.gson.GsonBuilder}
|
||||
* to configure a {@link org.mcteam.factions.gson.Gson} instance to properly translate Java field
|
||||
* names into the desired JSON field names.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public enum FieldNamingPolicy {
|
||||
/**
|
||||
* Using this naming policy with Gson will ensure that the first "letter" of the Java
|
||||
* field name is capitalized when serialized to its JSON form.
|
||||
*
|
||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
||||
* <ul>
|
||||
* <li>someFieldName ---> SomeFieldName</li>
|
||||
* <li>_someFieldName ---> _SomeFieldName</li>
|
||||
* </ul>
|
||||
*/
|
||||
UPPER_CAMEL_CASE(new ModifyFirstLetterNamingPolicy(
|
||||
ModifyFirstLetterNamingPolicy.LetterModifier.UPPER)),
|
||||
|
||||
/**
|
||||
* Using this naming policy with Gson will ensure that the first "letter" of the Java
|
||||
* field name is capitalized when serialized to its JSON form and the words will be
|
||||
* separated by a space.
|
||||
*
|
||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
||||
* <ul>
|
||||
* <li>someFieldName ---> Some Field Name</li>
|
||||
* <li>_someFieldName ---> _Some Field Name</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
UPPER_CAMEL_CASE_WITH_SPACES(new UpperCamelCaseSeparatorNamingPolicy(" ")),
|
||||
|
||||
/**
|
||||
* Using this naming policy with Gson will modify the Java Field name from its camel cased
|
||||
* form to a lower case field name where each word is separated by an underscore (_).
|
||||
*
|
||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
||||
* <ul>
|
||||
* <li>someFieldName ---> some_field_name</li>
|
||||
* <li>_someFieldName ---> _some_field_name</li>
|
||||
* <li>aStringField ---> a_string_field</li>
|
||||
* <li>aURL ---> a_u_r_l</li>
|
||||
* </ul>
|
||||
*/
|
||||
LOWER_CASE_WITH_UNDERSCORES(new LowerCamelCaseSeparatorNamingPolicy("_")),
|
||||
|
||||
/**
|
||||
* Using this naming policy with Gson will modify the Java Field name from its camel cased
|
||||
* form to a lower case field name where each word is separated by a dash (-).
|
||||
*
|
||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
||||
* <ul>
|
||||
* <li>someFieldName ---> some-field-name</li>
|
||||
* <li>_someFieldName ---> _some-field-name</li>
|
||||
* <li>aStringField ---> a-string-field</li>
|
||||
* <li>aURL ---> a-u-r-l</li>
|
||||
* </ul>
|
||||
* Using dashes in JavaScript is not recommended since dash is also used for a minus sign in
|
||||
* expressions. This requires that a field named with dashes is always accessed as a quoted
|
||||
* property like {@code myobject['my-field']}. Accessing it as an object field
|
||||
* {@code myobject.my-field} will result in an unintended javascript expression.
|
||||
* @since 1.4
|
||||
*/
|
||||
LOWER_CASE_WITH_DASHES(new LowerCamelCaseSeparatorNamingPolicy("-"));
|
||||
|
||||
private final FieldNamingStrategy2 namingPolicy;
|
||||
|
||||
private FieldNamingPolicy(FieldNamingStrategy2 namingPolicy) {
|
||||
this.namingPolicy = namingPolicy;
|
||||
}
|
||||
|
||||
FieldNamingStrategy2 getFieldNamingPolicy() {
|
||||
return namingPolicy;
|
||||
}
|
||||
}
|
40
src/org/mcteam/factions/gson/FieldNamingStrategy.java
Normal file
40
src/org/mcteam/factions/gson/FieldNamingStrategy.java
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* A mechanism for providing custom field naming in Gson. This allows the client code to translate
|
||||
* field names into a particular convention that is not supported as a normal Java field
|
||||
* declaration rules. For example, Java does not support "-" characters in a field name.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @since 1.3
|
||||
*/
|
||||
public interface FieldNamingStrategy {
|
||||
|
||||
/**
|
||||
* Translates the field name into its JSON field name representation.
|
||||
*
|
||||
* @param f the field object that we are translating
|
||||
* @return the translated field name.
|
||||
* @since 1.3
|
||||
*/
|
||||
public String translateName(Field f);
|
||||
}
|
38
src/org/mcteam/factions/gson/FieldNamingStrategy2.java
Normal file
38
src/org/mcteam/factions/gson/FieldNamingStrategy2.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* The new mechanism for providing custom field naming in Gson. This allows the client code
|
||||
* to translate field names into a particular convention that is not supported as a normal
|
||||
* Java field declaration rules. For example, Java does not support "-" characters in a
|
||||
* field name.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
interface FieldNamingStrategy2 {
|
||||
|
||||
/**
|
||||
* Translates the field name into its JSON field name representation.
|
||||
*
|
||||
* @param f the field that is being translated
|
||||
* @return the translated field name.
|
||||
* @since 1.3
|
||||
*/
|
||||
public String translateName(FieldAttributes f);
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* Adapts the old "deprecated" {@link FieldNamingStrategy} to the new {@link FieldNamingStrategy2}
|
||||
* type.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 {
|
||||
private final FieldNamingStrategy adaptee;
|
||||
|
||||
public FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) {
|
||||
Preconditions.checkNotNull(adaptee);
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public String translateName(FieldAttributes f) {
|
||||
return adaptee.translateName(f.getFieldObject());
|
||||
}
|
||||
}
|
70
src/org/mcteam/factions/gson/GenericArrayTypeImpl.java
Normal file
70
src/org/mcteam/factions/gson/GenericArrayTypeImpl.java
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* An simple pojo-like immutable instance of the {@link GenericArrayType}. This object provides
|
||||
* us the ability to create reflective types on demand. This object is required for support
|
||||
* object similar to the one defined below:
|
||||
* <pre>
|
||||
* class Foo<T> {
|
||||
* private final List<T>[] arrayOfListT;
|
||||
*
|
||||
* Foo(List<T>[] arrayList) {
|
||||
* this.arrayOfListT = arrayList;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>During parsing or serialization, we know the real variable type parameter {@code T},
|
||||
* so we can build a new {@code GenericTypeArray} with the "real" type parameters and
|
||||
* pass that object along instead.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class GenericArrayTypeImpl implements GenericArrayType {
|
||||
|
||||
private final Type genericComponentType;
|
||||
|
||||
public GenericArrayTypeImpl(Type genericComponentType) {
|
||||
this.genericComponentType = genericComponentType;
|
||||
}
|
||||
|
||||
public Type getGenericComponentType() {
|
||||
return genericComponentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof GenericArrayType)) {
|
||||
return false;
|
||||
}
|
||||
GenericArrayType that = (GenericArrayType) o;
|
||||
Type thatComponentType = that.getGenericComponentType();
|
||||
return genericComponentType == null ?
|
||||
thatComponentType == null : genericComponentType.equals(thatComponentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (genericComponentType == null) ? 0 : genericComponentType.hashCode();
|
||||
}
|
||||
}
|
597
src/org/mcteam/factions/gson/Gson.java
Normal file
597
src/org/mcteam/factions/gson/Gson.java
Normal file
@ -0,0 +1,597 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mcteam.factions.gson.JsonSerializationContextDefault;
|
||||
import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonToken;
|
||||
import org.mcteam.factions.gson.stream.JsonWriter;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
|
||||
/**
|
||||
* This is the main class for using Gson. Gson is typically used by first constructing a
|
||||
* Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)}
|
||||
* methods on it.
|
||||
*
|
||||
* <p>You can create a Gson instance by invoking {@code new Gson()} if the default configuration
|
||||
* is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various
|
||||
* configuration options such as versioning support, pretty printing, custom
|
||||
* {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.</p>
|
||||
*
|
||||
* <p>Here is an example of how Gson is used for a simple Class:
|
||||
*
|
||||
* <pre>
|
||||
* Gson gson = new Gson(); // Or use new GsonBuilder().create();
|
||||
* MyType target = new MyType();
|
||||
* String json = gson.toJson(target); // serializes target to Json
|
||||
* MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
|
||||
* </pre></p>
|
||||
*
|
||||
* <p>If the object that your are serializing/deserializing is a {@code ParameterizedType}
|
||||
* (i.e. contains at least one type parameter and may be an array) then you must use the
|
||||
* {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Here is an
|
||||
* example for serializing and deserialing a {@code ParameterizedType}:
|
||||
*
|
||||
* <pre>
|
||||
* Type listType = new TypeToken<List<String>>() {}.getType();
|
||||
* List<String> target = new LinkedList<String>();
|
||||
* target.add("blah");
|
||||
*
|
||||
* Gson gson = new Gson();
|
||||
* String json = gson.toJson(target, listType);
|
||||
* List<String> target2 = gson.fromJson(json, listType);
|
||||
* </pre></p>
|
||||
*
|
||||
* <p>See the <a href="https://sites.google.com/site/gson/gson-user-guide">Gson User Guide</a>
|
||||
* for a more complete set of examples.</p>
|
||||
*
|
||||
* @see org.mcteam.factions.gson.reflect.TypeToken
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class Gson {
|
||||
|
||||
//TODO(inder): get rid of all the registerXXX methods and take all such parameters in the
|
||||
// constructor instead. At the minimum, mark those methods private.
|
||||
|
||||
private static final String NULL_STRING = "null";
|
||||
|
||||
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
||||
|
||||
// Default instances of plug-ins
|
||||
static final AnonymousAndLocalClassExclusionStrategy DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY =
|
||||
new AnonymousAndLocalClassExclusionStrategy();
|
||||
static final SyntheticFieldExclusionStrategy DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY =
|
||||
new SyntheticFieldExclusionStrategy(true);
|
||||
static final ModifierBasedExclusionStrategy DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY =
|
||||
new ModifierBasedExclusionStrategy(new int[] { Modifier.TRANSIENT, Modifier.STATIC });
|
||||
static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY =
|
||||
new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy());
|
||||
|
||||
private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY =
|
||||
createExclusionStrategy(VersionConstants.IGNORE_VERSIONS);
|
||||
|
||||
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
|
||||
|
||||
private final ExclusionStrategy serializationStrategy;
|
||||
|
||||
private final ExclusionStrategy deserializationStrategy;
|
||||
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final MappedObjectConstructor objectConstructor;
|
||||
|
||||
/** Map containing Type or Class objects as keys */
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
|
||||
/** Map containing Type or Class objects as keys */
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
|
||||
private final boolean serializeNulls;
|
||||
private final boolean htmlSafe;
|
||||
private final boolean generateNonExecutableJson;
|
||||
private final boolean prettyPrinting;
|
||||
|
||||
/**
|
||||
* Constructs a Gson object with default configuration. The default configuration has the
|
||||
* following settings:
|
||||
* <ul>
|
||||
* <li>The JSON generated by <code>toJson</code> methods is in compact representation. This
|
||||
* means that all the unneeded white-space is removed. You can change this behavior with
|
||||
* {@link GsonBuilder#setPrettyPrinting()}. </li>
|
||||
* <li>The generated JSON omits all the fields that are null. Note that nulls in arrays are
|
||||
* kept as is since an array is an ordered list. Moreover, if a field is not null, but its
|
||||
* generated JSON is empty, the field is kept. You can configure Gson to serialize null values
|
||||
* by setting {@link GsonBuilder#serializeNulls()}.</li>
|
||||
* <li>Gson provides default serialization and deserialization for Enums, {@link Map},
|
||||
* {@link java.net.URL}, {@link java.net.URI}, {@link java.util.Locale}, {@link java.util.Date},
|
||||
* {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer
|
||||
* to change the default representation, you can do so by registering a type adapter through
|
||||
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}. </li>
|
||||
* <li>The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format
|
||||
* ignores the millisecond portion of the date during serialization. You can change
|
||||
* this by invoking {@link GsonBuilder#setDateFormat(int)} or
|
||||
* {@link GsonBuilder#setDateFormat(String)}. </li>
|
||||
* <li>By default, Gson ignores the {@link org.mcteam.factions.gson.annotations.Expose} annotation.
|
||||
* You can enable Gson to serialize/deserialize only those fields marked with this annotation
|
||||
* through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}. </li>
|
||||
* <li>By default, Gson ignores the {@link org.mcteam.factions.gson.annotations.Since} annotation. You
|
||||
* can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.</li>
|
||||
* <li>The default field naming policy for the output Json is same as in Java. So, a Java class
|
||||
* field <code>versionNumber</code> will be output as <code>"versionNumber@quot;</code> in
|
||||
* Json. The same rules are applied for mapping incoming Json to the Java classes. You can
|
||||
* change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.</li>
|
||||
* <li>By default, Gson excludes <code>transient</code> or <code>static</code> fields from
|
||||
* consideration for serialization and deserialization. You can change this behavior through
|
||||
* {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public Gson() {
|
||||
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
|
||||
new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
|
||||
false, DefaultTypeAdapters.getDefaultSerializers(),
|
||||
DefaultTypeAdapters.getDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false);
|
||||
}
|
||||
|
||||
Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy,
|
||||
FieldNamingStrategy2 fieldNamingPolicy, MappedObjectConstructor objectConstructor,
|
||||
boolean serializeNulls, ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) {
|
||||
this.serializationStrategy = serializationStrategy;
|
||||
this.deserializationStrategy = deserializationStrategy;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.objectConstructor = objectConstructor;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
this.generateNonExecutableJson = generateNonExecutableGson;
|
||||
this.htmlSafe = htmlSafe;
|
||||
this.prettyPrinting = prettyPrinting;
|
||||
}
|
||||
|
||||
private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy strategy) {
|
||||
return new ObjectNavigatorFactory(strategy, fieldNamingPolicy);
|
||||
}
|
||||
|
||||
private static ExclusionStrategy createExclusionStrategy(double version) {
|
||||
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
|
||||
strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
|
||||
if (version != VersionConstants.IGNORE_VERSIONS) {
|
||||
strategies.add(new VersionExclusionStrategy(version));
|
||||
}
|
||||
return new DisjunctionExclusionStrategy(strategies);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the specified object into its equivalent representation as a tree of
|
||||
* {@link JsonElement}s. This method should be used when the specified object is not a generic
|
||||
* type. This method uses {@link Class#getClass()} to get the type for the specified object, but
|
||||
* the {@code getClass()} loses the generic type information because of the Type Erasure feature
|
||||
* of Java. Note that this method works fine if the any of the object fields are of generic type,
|
||||
* just the object itself should not be of a generic type. If the object is of generic type, use
|
||||
* {@link #toJsonTree(Object, Type)} instead.
|
||||
*
|
||||
* @param src the object for which Json representation is to be created setting for Gson
|
||||
* @return Json representation of {@code src}.
|
||||
* @since 1.4
|
||||
*/
|
||||
public JsonElement toJsonTree(Object src) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
return toJsonTree(src, src.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the specified object, including those of generic types, into its
|
||||
* equivalent representation as a tree of {@link JsonElement}s. This method must be used if the
|
||||
* specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)}
|
||||
* instead.
|
||||
*
|
||||
* @param src the object for which JSON representation is to be created
|
||||
* @param typeOfSrc The specific genericized type of src. You can obtain
|
||||
* this type by using the {@link org.mcteam.factions.gson.reflect.TypeToken} class. For example,
|
||||
* to get the type for {@code Collection<Foo>}, you should use:
|
||||
* <pre>
|
||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
||||
* </pre>
|
||||
* @return Json representation of {@code src}
|
||||
* @since 1.4
|
||||
*/
|
||||
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
JsonSerializationContextDefault context = new JsonSerializationContextDefault(
|
||||
createDefaultObjectNavigatorFactory(serializationStrategy), serializeNulls, serializers);
|
||||
return context.serialize(src, typeOfSrc, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the specified object into its equivalent Json representation.
|
||||
* This method should be used when the specified object is not a generic type. This method uses
|
||||
* {@link Class#getClass()} to get the type for the specified object, but the
|
||||
* {@code getClass()} loses the generic type information because of the Type Erasure feature
|
||||
* of Java. Note that this method works fine if the any of the object fields are of generic type,
|
||||
* just the object itself should not be of a generic type. If the object is of generic type, use
|
||||
* {@link #toJson(Object, Type)} instead. If you want to write out the object to a
|
||||
* {@link Writer}, use {@link #toJson(Object, Appendable)} instead.
|
||||
*
|
||||
* @param src the object for which Json representation is to be created setting for Gson
|
||||
* @return Json representation of {@code src}.
|
||||
*/
|
||||
public String toJson(Object src) {
|
||||
if (src == null) {
|
||||
return serializeNulls ? NULL_STRING : "";
|
||||
}
|
||||
return toJson(src, src.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the specified object, including those of generic types, into its
|
||||
* equivalent Json representation. This method must be used if the specified object is a generic
|
||||
* type. For non-generic objects, use {@link #toJson(Object)} instead. If you want to write out
|
||||
* the object to a {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} instead.
|
||||
*
|
||||
* @param src the object for which JSON representation is to be created
|
||||
* @param typeOfSrc The specific genericized type of src. You can obtain
|
||||
* this type by using the {@link org.mcteam.factions.gson.reflect.TypeToken} class. For example,
|
||||
* to get the type for {@code Collection<Foo>}, you should use:
|
||||
* <pre>
|
||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
||||
* </pre>
|
||||
* @return Json representation of {@code src}
|
||||
*/
|
||||
public String toJson(Object src, Type typeOfSrc) {
|
||||
StringWriter writer = new StringWriter();
|
||||
toJson(toJsonTree(src, typeOfSrc), writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the specified object into its equivalent Json representation.
|
||||
* This method should be used when the specified object is not a generic type. This method uses
|
||||
* {@link Class#getClass()} to get the type for the specified object, but the
|
||||
* {@code getClass()} loses the generic type information because of the Type Erasure feature
|
||||
* of Java. Note that this method works fine if the any of the object fields are of generic type,
|
||||
* just the object itself should not be of a generic type. If the object is of generic type, use
|
||||
* {@link #toJson(Object, Type, Appendable)} instead.
|
||||
*
|
||||
* @param src the object for which Json representation is to be created setting for Gson
|
||||
* @param writer Writer to which the Json representation needs to be written
|
||||
* @throws JsonIOException if there was a problem writing to the writer
|
||||
* @since 1.2
|
||||
*/
|
||||
public void toJson(Object src, Appendable writer) throws JsonIOException {
|
||||
try {
|
||||
if (src != null) {
|
||||
toJson(src, src.getClass(), writer);
|
||||
} else if (serializeNulls) {
|
||||
writeOutNullString(writer);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method serializes the specified object, including those of generic types, into its
|
||||
* equivalent Json representation. This method must be used if the specified object is a generic
|
||||
* type. For non-generic objects, use {@link #toJson(Object, Appendable)} instead.
|
||||
*
|
||||
* @param src the object for which JSON representation is to be created
|
||||
* @param typeOfSrc The specific genericized type of src. You can obtain
|
||||
* this type by using the {@link org.mcteam.factions.gson.reflect.TypeToken} class. For example,
|
||||
* to get the type for {@code Collection<Foo>}, you should use:
|
||||
* <pre>
|
||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
||||
* </pre>
|
||||
* @param writer Writer to which the Json representation of src needs to be written.
|
||||
* @throws JsonIOException if there was a problem writing to the writer
|
||||
* @since 1.2
|
||||
*/
|
||||
public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
|
||||
JsonElement jsonElement = toJsonTree(src, typeOfSrc);
|
||||
toJson(jsonElement, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the JSON representation of {@code src} of type {@code typeOfSrc} to
|
||||
* {@code writer}.
|
||||
* @throws JsonIOException if there was a problem writing to the writer
|
||||
*/
|
||||
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
|
||||
toJson(toJsonTree(src, typeOfSrc), writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
|
||||
*
|
||||
* @param jsonElement root of a tree of {@link JsonElement}s
|
||||
* @return JSON String representation of the tree
|
||||
* @since 1.4
|
||||
*/
|
||||
public String toJson(JsonElement jsonElement) {
|
||||
StringWriter writer = new StringWriter();
|
||||
toJson(jsonElement, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out the equivalent JSON for a tree of {@link JsonElement}s.
|
||||
*
|
||||
* @param jsonElement root of a tree of {@link JsonElement}s
|
||||
* @param writer Writer to which the Json representation needs to be written
|
||||
* @throws JsonIOException if there was a problem writing to the writer
|
||||
* @since 1.4
|
||||
*/
|
||||
public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {
|
||||
try {
|
||||
if (generateNonExecutableJson) {
|
||||
writer.append(JSON_NON_EXECUTABLE_PREFIX);
|
||||
}
|
||||
JsonWriter jsonWriter = new JsonWriter(Streams.writerForAppendable(writer));
|
||||
if (prettyPrinting) {
|
||||
jsonWriter.setIndent(" ");
|
||||
}
|
||||
toJson(jsonElement, jsonWriter);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the JSON for {@code jsonElement} to {@code writer}.
|
||||
* @throws JsonIOException if there was a problem writing to the writer
|
||||
*/
|
||||
public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException {
|
||||
boolean oldLenient = writer.isLenient();
|
||||
writer.setLenient(true);
|
||||
boolean oldHtmlSafe = writer.isHtmlSafe();
|
||||
writer.setHtmlSafe(htmlSafe);
|
||||
try {
|
||||
Streams.write(jsonElement, serializeNulls, writer);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
} finally {
|
||||
writer.setLenient(oldLenient);
|
||||
writer.setHtmlSafe(oldHtmlSafe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deserializes the specified Json into an object of the specified class. It is not
|
||||
* suitable to use if the specified class is a generic type since it will not have the generic
|
||||
* type information because of the Type Erasure feature of Java. Therefore, this method should not
|
||||
* be used if the desired type is a generic type. Note that this method works fine if the any of
|
||||
* the fields of the specified object are generics, just the object itself should not be a
|
||||
* generic type. For the cases when the object is of generic type, invoke
|
||||
* {@link #fromJson(String, Type)}. If you have the Json in a {@link Reader} instead of
|
||||
* a String, use {@link #fromJson(Reader, Class)} instead.
|
||||
*
|
||||
* @param <T> the type of the desired object
|
||||
* @param json the string from which the object is to be deserialized
|
||||
* @param classOfT the class of T
|
||||
* @return an object of type T from the string
|
||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
||||
* classOfT
|
||||
*/
|
||||
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
|
||||
Object object = fromJson(json, (Type) classOfT);
|
||||
return Primitives.wrap(classOfT).cast(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deserializes the specified Json into an object of the specified type. This method
|
||||
* is useful if the specified object is a generic type. For non-generic objects, use
|
||||
* {@link #fromJson(String, Class)} instead. If you have the Json in a {@link Reader} instead of
|
||||
* a String, use {@link #fromJson(Reader, Type)} instead.
|
||||
*
|
||||
* @param <T> the type of the desired object
|
||||
* @param json the string from which the object is to be deserialized
|
||||
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
||||
* {@link org.mcteam.factions.gson.reflect.TypeToken} class. For example, to get the type for
|
||||
* {@code Collection<Foo>}, you should use:
|
||||
* <pre>
|
||||
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
||||
* </pre>
|
||||
* @return an object of type T from the string
|
||||
* @throws JsonParseException if json is not a valid representation for an object of type typeOfT
|
||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
StringReader reader = new StringReader(json);
|
||||
T target = (T) fromJson(reader, typeOfT);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deserializes the Json read from the specified reader into an object of the
|
||||
* specified class. It is not suitable to use if the specified class is a generic type since it
|
||||
* will not have the generic type information because of the Type Erasure feature of Java.
|
||||
* Therefore, this method should not be used if the desired type is a generic type. Note that
|
||||
* this method works fine if the any of the fields of the specified object are generics, just the
|
||||
* object itself should not be a generic type. For the cases when the object is of generic type,
|
||||
* invoke {@link #fromJson(Reader, Type)}. If you have the Json in a String form instead of a
|
||||
* {@link Reader}, use {@link #fromJson(String, Class)} instead.
|
||||
*
|
||||
* @param <T> the type of the desired object
|
||||
* @param json the reader producing the Json from which the object is to be deserialized.
|
||||
* @param classOfT the class of T
|
||||
* @return an object of type T from the string
|
||||
* @throws JsonIOException if there was a problem reading from the Reader
|
||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
||||
* @since 1.2
|
||||
*/
|
||||
public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {
|
||||
JsonReader jsonReader = new JsonReader(json);
|
||||
Object object = fromJson(jsonReader, classOfT);
|
||||
assertFullConsumption(object, jsonReader);
|
||||
return Primitives.wrap(classOfT).cast(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deserializes the Json read from the specified reader into an object of the
|
||||
* specified type. This method is useful if the specified object is a generic type. For
|
||||
* non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the Json in a
|
||||
* String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead.
|
||||
*
|
||||
* @param <T> the type of the desired object
|
||||
* @param json the reader producing Json from which the object is to be deserialized
|
||||
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
||||
* {@link org.mcteam.factions.gson.reflect.TypeToken} class. For example, to get the type for
|
||||
* {@code Collection<Foo>}, you should use:
|
||||
* <pre>
|
||||
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
||||
* </pre>
|
||||
* @return an object of type T from the json
|
||||
* @throws JsonIOException if there was a problem reading from the Reader
|
||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
||||
* @since 1.2
|
||||
*/
|
||||
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
||||
JsonReader jsonReader = new JsonReader(json);
|
||||
T object = this.<T>fromJson(jsonReader, typeOfT);
|
||||
assertFullConsumption(object, jsonReader);
|
||||
return object;
|
||||
}
|
||||
|
||||
private static void assertFullConsumption(Object obj, JsonReader reader) {
|
||||
try {
|
||||
if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
|
||||
throw new JsonIOException("JSON document was not fully consumed.");
|
||||
}
|
||||
} catch (MalformedJsonException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next JSON value from {@code reader} and convert it to an object
|
||||
* of type {@code typeOfT}.
|
||||
* Since Type is not parameterized by T, this method is type unsafe and should be used carefully
|
||||
*
|
||||
* @throws JsonIOException if there was a problem writing to the Reader
|
||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
||||
boolean oldLenient = reader.isLenient();
|
||||
reader.setLenient(true);
|
||||
try {
|
||||
JsonElement root = Streams.parse(reader);
|
||||
return (T) fromJson(root, typeOfT);
|
||||
} finally {
|
||||
reader.setLenient(oldLenient);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deserializes the Json read from the specified parse tree into an object of the
|
||||
* specified type. It is not suitable to use if the specified class is a generic type since it
|
||||
* will not have the generic type information because of the Type Erasure feature of Java.
|
||||
* Therefore, this method should not be used if the desired type is a generic type. Note that
|
||||
* this method works fine if the any of the fields of the specified object are generics, just the
|
||||
* object itself should not be a generic type. For the cases when the object is of generic type,
|
||||
* invoke {@link #fromJson(JsonElement, Type)}.
|
||||
* @param <T> the type of the desired object
|
||||
* @param json the root of the parse tree of {@link JsonElement}s from which the object is to
|
||||
* be deserialized
|
||||
* @param classOfT The class of T
|
||||
* @return an object of type T from the json
|
||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
|
||||
* @since 1.3
|
||||
*/
|
||||
public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
|
||||
Object object = fromJson(json, (Type) classOfT);
|
||||
return Primitives.wrap(classOfT).cast(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method deserializes the Json read from the specified parse tree into an object of the
|
||||
* specified type. This method is useful if the specified object is a generic type. For
|
||||
* non-generic objects, use {@link #fromJson(JsonElement, Class)} instead.
|
||||
*
|
||||
* @param <T> the type of the desired object
|
||||
* @param json the root of the parse tree of {@link JsonElement}s from which the object is to
|
||||
* be deserialized
|
||||
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
||||
* {@link org.mcteam.factions.gson.reflect.TypeToken} class. For example, to get the type for
|
||||
* {@code Collection<Foo>}, you should use:
|
||||
* <pre>
|
||||
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
||||
* </pre>
|
||||
* @return an object of type T from the json
|
||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
|
||||
* @since 1.3
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
JsonDeserializationContext context = new JsonDeserializationContextDefault(
|
||||
createDefaultObjectNavigatorFactory(deserializationStrategy), deserializers,
|
||||
objectConstructor);
|
||||
T target = (T) context.deserialize(json, typeOfT);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the {@link #NULL_STRING} to the {@code writer} object.
|
||||
*
|
||||
* @param writer the object to append the null value to
|
||||
*/
|
||||
private void writeOutNullString(Appendable writer) throws IOException {
|
||||
writer.append(NULL_STRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{")
|
||||
.append("serializeNulls:").append(serializeNulls)
|
||||
.append(",serializers:").append(serializers)
|
||||
.append(",deserializers:").append(deserializers)
|
||||
|
||||
// using the name instanceCreator instead of ObjectConstructor since the users of Gson are
|
||||
// more familiar with the concept of Instance Creators. Moreover, the objectConstructor is
|
||||
// just a utility class around instance creators, and its toString() only displays them.
|
||||
.append(",instanceCreators:").append(objectConstructor)
|
||||
.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
571
src/org/mcteam/factions/gson/GsonBuilder.java
Normal file
571
src/org/mcteam/factions/gson/GsonBuilder.java
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mcteam.factions.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
|
||||
* options other than the default. For {@link Gson} with default configuration, it is simpler to
|
||||
* use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its
|
||||
* various configuration methods, and finally calling create.</p>
|
||||
*
|
||||
* <p>The following is an example shows how to use the {@code GsonBuilder} to construct a Gson
|
||||
* instance:
|
||||
*
|
||||
* <pre>
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .registerTypeAdapter(Id.class, new IdTypeAdapter())
|
||||
* .serializeNulls()
|
||||
* .setDateFormat(DateFormat.LONG)
|
||||
* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
|
||||
* .setPrettyPrinting()
|
||||
* .setVersion(1.0)
|
||||
* .create();
|
||||
* </pre></p>
|
||||
*
|
||||
* <p>NOTE: the order of invocation of configuration methods does not matter.</p>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class GsonBuilder {
|
||||
private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
|
||||
new InnerClassExclusionStrategy();
|
||||
private static final ExposeAnnotationSerializationExclusionStrategy
|
||||
exposeAnnotationSerializationExclusionStrategy =
|
||||
new ExposeAnnotationSerializationExclusionStrategy();
|
||||
private static final ExposeAnnotationDeserializationExclusionStrategy
|
||||
exposeAnnotationDeserializationExclusionStrategy =
|
||||
new ExposeAnnotationDeserializationExclusionStrategy();
|
||||
|
||||
private final Collection<ExclusionStrategy> exclusionStrategies =
|
||||
new HashSet<ExclusionStrategy>();
|
||||
|
||||
private double ignoreVersionsAfter;
|
||||
private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy;
|
||||
private boolean serializeInnerClasses;
|
||||
private boolean excludeFieldsWithoutExposeAnnotation;
|
||||
private LongSerializationPolicy longSerializationPolicy;
|
||||
private FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private boolean serializeNulls;
|
||||
private String datePattern;
|
||||
private int dateStyle;
|
||||
private int timeStyle;
|
||||
private boolean serializeSpecialFloatingPointValues;
|
||||
private boolean escapeHtmlChars;
|
||||
private boolean prettyPrinting;
|
||||
private boolean generateNonExecutableJson;
|
||||
|
||||
/**
|
||||
* Creates a GsonBuilder instance that can be used to build Gson with various configuration
|
||||
* settings. GsonBuilder follows the builder pattern, and it is typically used by first
|
||||
* invoking various configuration methods to set desired options, and finally calling
|
||||
* {@link #create()}.
|
||||
*/
|
||||
public GsonBuilder() {
|
||||
// add default exclusion strategies
|
||||
exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
|
||||
// setup default values
|
||||
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
|
||||
serializeInnerClasses = true;
|
||||
prettyPrinting = false;
|
||||
escapeHtmlChars = true;
|
||||
modifierBasedExclusionStrategy = Gson.DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY;
|
||||
excludeFieldsWithoutExposeAnnotation = false;
|
||||
longSerializationPolicy = LongSerializationPolicy.DEFAULT;
|
||||
fieldNamingPolicy = Gson.DEFAULT_NAMING_POLICY;
|
||||
instanceCreators = new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||
serializers = new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
||||
deserializers = new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
||||
serializeNulls = false;
|
||||
dateStyle = DateFormat.DEFAULT;
|
||||
timeStyle = DateFormat.DEFAULT;
|
||||
serializeSpecialFloatingPointValues = false;
|
||||
generateNonExecutableJson = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to enable versioning support.
|
||||
*
|
||||
* @param ignoreVersionsAfter any field or type marked with a version higher than this value
|
||||
* are ignored during serialization or deserialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder setVersion(double ignoreVersionsAfter) {
|
||||
this.ignoreVersionsAfter = ignoreVersionsAfter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to excludes all class fields that have the specified modifiers. By default,
|
||||
* Gson will exclude all fields marked transient or static. This method will override that
|
||||
* behavior.
|
||||
*
|
||||
* @param modifiers the field modifiers. You must use the modifiers specified in the
|
||||
* {@link java.lang.reflect.Modifier} class. For example,
|
||||
* {@link java.lang.reflect.Modifier#TRANSIENT},
|
||||
* {@link java.lang.reflect.Modifier#STATIC}.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder excludeFieldsWithModifiers(int... modifiers) {
|
||||
modifierBasedExclusionStrategy = new ModifierBasedExclusionStrategy(modifiers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some
|
||||
* special text. This prevents attacks from third-party sites through script sourcing. See
|
||||
* <a href="http://code.google.com/p/google-gson/issues/detail?id=42">Gson Issue 42</a>
|
||||
* for details.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder generateNonExecutableJson() {
|
||||
this.generateNonExecutableJson = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to exclude all fields from consideration for serialization or deserialization
|
||||
* that do not have the {@link org.mcteam.factions.gson.annotations.Expose} annotation.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
|
||||
excludeFieldsWithoutExposeAnnotation = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure Gson to serialize null fields. By default, Gson omits all fields that are null
|
||||
* during serialization.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.2
|
||||
*/
|
||||
public GsonBuilder serializeNulls() {
|
||||
this.serializeNulls = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to exclude inner classes during serialization.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder disableInnerClassSerialization() {
|
||||
serializeInnerClasses = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply a specific serialization policy for {@code Long} and {@code long}
|
||||
* objects.
|
||||
*
|
||||
* @param serializationPolicy the particular policy to use for serializing longs.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) {
|
||||
this.longSerializationPolicy = serializationPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply a specific naming policy to an object's field during serialization
|
||||
* and deserialization.
|
||||
*
|
||||
* @param namingConvention the JSON field naming convention to use for serialization and
|
||||
* deserialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {
|
||||
return setFieldNamingStrategy(namingConvention.getFieldNamingPolicy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply a specific naming policy strategy to an object's field during
|
||||
* serialization and deserialization.
|
||||
*
|
||||
* @param fieldNamingStrategy the actual naming strategy to apply to the fields
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
|
||||
return setFieldNamingStrategy(new FieldNamingStrategy2Adapter(fieldNamingStrategy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply a specific naming policy strategy to an object's field during
|
||||
* serialization and deserialization.
|
||||
*
|
||||
* @param fieldNamingStrategy the actual naming strategy to apply to the fields
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
GsonBuilder setFieldNamingStrategy(FieldNamingStrategy2 fieldNamingStrategy) {
|
||||
this.fieldNamingPolicy =
|
||||
new SerializedNameAnnotationInterceptingNamingPolicy(fieldNamingStrategy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply a set of exclusion strategies during both serialization and
|
||||
* deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
|
||||
* This means that if one of the {@code strategies} suggests that a field (or class) should be
|
||||
* skipped then that field (or object) is skipped during serializaiton/deserialization.
|
||||
*
|
||||
* @param strategies the set of strategy object to apply during object (de)serialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.4
|
||||
*/
|
||||
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
exclusionStrategies.add(strategy);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to output Json that fits in a page for pretty printing. This option only
|
||||
* affects Json serialization.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder setPrettyPrinting() {
|
||||
prettyPrinting = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, Gson escapes HTML characters such as < > etc. Use this option to configure
|
||||
* Gson to pass-through HTML characters as is.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder disableHtmlEscaping() {
|
||||
this.escapeHtmlChars = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to serialize {@code Date} objects according to the pattern provided. You can
|
||||
* call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
|
||||
* will be used to decide the serialization format.
|
||||
*
|
||||
* <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
|
||||
* class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
|
||||
* valid date and time patterns.</p>
|
||||
*
|
||||
* @param pattern the pattern that dates will be serialized/deserialized to/from
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.2
|
||||
*/
|
||||
public GsonBuilder setDateFormat(String pattern) {
|
||||
// TODO(Joel): Make this fail fast if it is an invalid date format
|
||||
this.datePattern = pattern;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to to serialize {@code Date} objects according to the style value provided.
|
||||
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
|
||||
* invocation will be used to decide the serialization format.
|
||||
*
|
||||
* <p>Note that this style value should be one of the predefined constants in the
|
||||
* {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
|
||||
* information on the valid style constants.</p>
|
||||
*
|
||||
* @param style the predefined date style that date objects will be serialized/deserialized
|
||||
* to/from
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.2
|
||||
*/
|
||||
public GsonBuilder setDateFormat(int style) {
|
||||
this.dateStyle = style;
|
||||
this.datePattern = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to to serialize {@code Date} objects according to the style value provided.
|
||||
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
|
||||
* invocation will be used to decide the serialization format.
|
||||
*
|
||||
* <p>Note that this style value should be one of the predefined constants in the
|
||||
* {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
|
||||
* information on the valid style constants.</p>
|
||||
*
|
||||
* @param dateStyle the predefined date style that date objects will be serialized/deserialized
|
||||
* to/from
|
||||
* @param timeStyle the predefined style for the time portion of the date objects
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.2
|
||||
*/
|
||||
public GsonBuilder setDateFormat(int dateStyle, int timeStyle) {
|
||||
this.dateStyle = dateStyle;
|
||||
this.timeStyle = timeStyle;
|
||||
this.datePattern = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson for custom serialization or deserialization. This method combines the
|
||||
* registration of an {@link InstanceCreator}, {@link JsonSerializer}, and a
|
||||
* {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
|
||||
* all the required interfaces for custom serialization with Gson. If an instance creator,
|
||||
* serializer or deserializer was previously registered for the specified {@code type}, it is
|
||||
* overwritten.
|
||||
*
|
||||
* @param type the type definition for the type adapter being registered
|
||||
* @param typeAdapter This object must implement at least one of the {@link InstanceCreator},
|
||||
* {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
|
||||
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter);
|
||||
}
|
||||
if (typeAdapter instanceof JsonSerializer<?>) {
|
||||
registerSerializer(type, (JsonSerializer<?>) typeAdapter);
|
||||
}
|
||||
if (typeAdapter instanceof JsonDeserializer<?>) {
|
||||
registerDeserializer(type, (JsonDeserializer<?>) typeAdapter);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to use a custom {@link InstanceCreator} for the specified type. If an instance
|
||||
* creator was previously registered for the specified class, it is overwritten. Since this method
|
||||
* takes a type instead of a Class object, it can be used to register a specific handler for a
|
||||
* generic type corresponding to a raw type.
|
||||
*
|
||||
* @param <T> the type for which instance creator is being registered
|
||||
* @param typeOfT The Type definition for T
|
||||
* @param instanceCreator the instance creator for T
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
private <T> GsonBuilder registerInstanceCreator(Type typeOfT,
|
||||
InstanceCreator<? extends T> instanceCreator) {
|
||||
instanceCreators.register(typeOfT, instanceCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to use a custom JSON serializer for the specified type. You should use this
|
||||
* method if you want to register different serializers for different generic types corresponding
|
||||
* to a raw type.
|
||||
*
|
||||
* @param <T> the type for which the serializer is being registered
|
||||
* @param typeOfT The type definition for T
|
||||
* @param serializer the custom serializer
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
private <T> GsonBuilder registerSerializer(Type typeOfT, final JsonSerializer<T> serializer) {
|
||||
serializers.register(typeOfT, serializer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to use a custom JSON deserializer for the specified type. You should use this
|
||||
* method if you want to register different deserializers for different generic types
|
||||
* corresponding to a raw type.
|
||||
*
|
||||
* @param <T> the type for which the deserializer is being registered
|
||||
* @param typeOfT The type definition for T
|
||||
* @param deserializer the custom deserializer
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
private <T> GsonBuilder registerDeserializer(Type typeOfT, JsonDeserializer<T> deserializer) {
|
||||
deserializers.register(typeOfT, new JsonDeserializerExceptionWrapper<T>(deserializer));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
|
||||
* This method combines the registration of an {@link InstanceCreator}, {@link JsonSerializer},
|
||||
* and a {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter}
|
||||
* implements all the required interfaces for custom serialization with Gson.
|
||||
* If an instance creator, serializer or deserializer was previously registered for the specified
|
||||
* type hierarchy, it is overwritten. If an instance creator, serializer or deserializer is
|
||||
* registered for a specific type in the type hierarchy, it will be invoked instead of the one
|
||||
* registered for the type hierarchy.
|
||||
*
|
||||
* @param baseType the class definition for the type adapter being registered for the base class
|
||||
* or interface
|
||||
* @param typeAdapter This object must implement at least one of the {@link InstanceCreator},
|
||||
* {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
|
||||
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator<?>) typeAdapter);
|
||||
}
|
||||
if (typeAdapter instanceof JsonSerializer<?>) {
|
||||
registerSerializerForTypeHierarchy(baseType, (JsonSerializer<?>) typeAdapter);
|
||||
}
|
||||
if (typeAdapter instanceof JsonDeserializer<?>) {
|
||||
registerDeserializerForTypeHierarchy(baseType, (JsonDeserializer<?>) typeAdapter);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerInstanceCreatorForTypeHierarchy(Class<?> classOfT,
|
||||
InstanceCreator<? extends T> instanceCreator) {
|
||||
instanceCreators.registerForTypeHierarchy(classOfT, instanceCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerSerializerForTypeHierarchy(Class<?> classOfT,
|
||||
final JsonSerializer<T> serializer) {
|
||||
serializers.registerForTypeHierarchy(classOfT, serializer);
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerDeserializerForTypeHierarchy(Class<?> classOfT,
|
||||
JsonDeserializer<T> deserializer) {
|
||||
deserializers.registerForTypeHierarchy(classOfT,
|
||||
new JsonDeserializerExceptionWrapper<T>(deserializer));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Section 2.4 of <a href="http://www.ietf.org/rfc/rfc4627.txt">JSON specification</a> disallows
|
||||
* special double values (NaN, Infinity, -Infinity). However,
|
||||
* <a href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf">Javascript
|
||||
* specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
|
||||
* values. Moreover, most JavaScript engines will accept these special values in JSON without
|
||||
* problem. So, at a practical level, it makes sense to accept these values as valid JSON even
|
||||
* though JSON specification disallows them.
|
||||
*
|
||||
* <p>Gson always accepts these special values during deserialization. However, it outputs
|
||||
* strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},
|
||||
* {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value
|
||||
* {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it
|
||||
* will throw an {@link IllegalArgumentException}. This method provides a way to override the
|
||||
* default behavior when you know that the JSON receiver will be able to handle these special
|
||||
* values.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder serializeSpecialFloatingPointValues() {
|
||||
this.serializeSpecialFloatingPointValues = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Gson} instance based on the current configuration. This method is free of
|
||||
* side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.
|
||||
*
|
||||
* @return an instance of Gson configured with the options currently set in this builder
|
||||
*/
|
||||
public Gson create() {
|
||||
List<ExclusionStrategy> serializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(exclusionStrategies);
|
||||
List<ExclusionStrategy> deserializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(exclusionStrategies);
|
||||
|
||||
serializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
deserializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
|
||||
if (!serializeInnerClasses) {
|
||||
serializationStrategies.add(innerClassExclusionStrategy);
|
||||
deserializationStrategies.add(innerClassExclusionStrategy);
|
||||
}
|
||||
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
|
||||
serializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
|
||||
deserializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
|
||||
}
|
||||
if (excludeFieldsWithoutExposeAnnotation) {
|
||||
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
|
||||
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
|
||||
}
|
||||
ExclusionStrategy serializationExclusionStrategy =
|
||||
new DisjunctionExclusionStrategy(serializationStrategies);
|
||||
ExclusionStrategy deserializationExclusionStrategy =
|
||||
new DisjunctionExclusionStrategy(deserializationStrategies);
|
||||
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> customSerializers = serializers.copyOf();
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> customDeserializers = deserializers.copyOf();
|
||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers,
|
||||
customDeserializers);
|
||||
|
||||
customSerializers.registerIfAbsent(DefaultTypeAdapters.getDefaultSerializers(
|
||||
serializeSpecialFloatingPointValues, longSerializationPolicy));
|
||||
|
||||
customDeserializers.registerIfAbsent(DefaultTypeAdapters.getDefaultDeserializers());
|
||||
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> customInstanceCreators =
|
||||
instanceCreators.copyOf();
|
||||
customInstanceCreators.registerIfAbsent(DefaultTypeAdapters.getDefaultInstanceCreators());
|
||||
|
||||
customSerializers.makeUnmodifiable();
|
||||
customDeserializers.makeUnmodifiable();
|
||||
instanceCreators.makeUnmodifiable();
|
||||
|
||||
MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
|
||||
|
||||
Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy,
|
||||
fieldNamingPolicy, objConstructor, serializeNulls, customSerializers,
|
||||
customDeserializers, generateNonExecutableJson, escapeHtmlChars, prettyPrinting);
|
||||
return gson;
|
||||
}
|
||||
|
||||
private static void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers) {
|
||||
DefaultDateTypeAdapter dateTypeAdapter = null;
|
||||
if (datePattern != null && !"".equals(datePattern.trim())) {
|
||||
dateTypeAdapter = new DefaultDateTypeAdapter(datePattern);
|
||||
} else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
|
||||
dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle);
|
||||
}
|
||||
|
||||
if (dateTypeAdapter != null) {
|
||||
if (!serializers.hasSpecificHandlerFor(Date.class)) {
|
||||
serializers.register(Date.class, dateTypeAdapter);
|
||||
}
|
||||
if (!deserializers.hasSpecificHandlerFor(Date.class)) {
|
||||
deserializers.register(Date.class, dateTypeAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Strategy for excluding inner classes.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
class InnerClassExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return isInnerClass(f.getDeclaredClass());
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return isInnerClass(clazz);
|
||||
}
|
||||
|
||||
private boolean isInnerClass(Class<?> clazz) {
|
||||
return clazz.isMemberClass() && !isStatic(clazz);
|
||||
}
|
||||
|
||||
private boolean isStatic(Class<?> clazz) {
|
||||
return (clazz.getModifiers() & Modifier.STATIC) != 0;
|
||||
}
|
||||
}
|
92
src/org/mcteam/factions/gson/InstanceCreator.java
Normal file
92
src/org/mcteam/factions/gson/InstanceCreator.java
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* This interface is implemented to create instances of a class that does not define a no-args
|
||||
* constructor. If you can modify the class, you should instead add a private, or public
|
||||
* no-args constructor. However, that is not possible for library classes, such as JDK classes, or
|
||||
* a third-party library that you do not have source-code of. In such cases, you should define an
|
||||
* instance creator for the class. Implementations of this interface should be registered with
|
||||
* {@link GsonBuilder#registerTypeAdapter(Type, Object)} method before Gson will be able to use
|
||||
* them.
|
||||
* <p>Let us look at an example where defining an InstanceCreator might be useful. The
|
||||
* {@code Id} class defined below does not have a default no-args constructor.</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class Id<T> {
|
||||
* private final Class<T> clazz;
|
||||
* private final long value;
|
||||
* public Id(Class<T> clazz, long value) {
|
||||
* this.clazz = clazz;
|
||||
* this.value = value;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>If Gson encounters an object of type {@code Id} during deserialization, it will throw an
|
||||
* exception. The easiest way to solve this problem will be to add a (public or private) no-args
|
||||
* constructor as follows:</p>
|
||||
*
|
||||
* <pre>
|
||||
* private Id() {
|
||||
* this(Object.class, 0L);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>However, let us assume that the developer does not have access to the source-code of the
|
||||
* {@code Id} class, or does not want to define a no-args constructor for it. The developer
|
||||
* can solve this problem by defining an {@code InstanceCreator} for {@code Id}:</p>
|
||||
*
|
||||
* <pre>
|
||||
* class IdInstanceCreator implements InstanceCreator<Id> {
|
||||
* public Id createInstance(Type type) {
|
||||
* return new Id(Object.class, 0L);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Note that it does not matter what the fields of the created instance contain since Gson will
|
||||
* overwrite them with the deserialized values specified in Json. You should also ensure that a
|
||||
* <i>new</i> object is returned, not a common object since its fields will be overwritten.
|
||||
* The developer will need to register {@code IdInstanceCreator} with Gson as follows:</p>
|
||||
*
|
||||
* <pre>
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the type of object that will be created by this implementation.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public interface InstanceCreator<T> {
|
||||
|
||||
/**
|
||||
* Gson invokes this call-back method during deserialization to create an instance of the
|
||||
* specified type. The fields of the returned instance are overwritten with the data present
|
||||
* in the Json. Since the prior contents of the object are destroyed and overwritten, do not
|
||||
* return an instance that is useful elsewhere. In particular, do not return a common instance,
|
||||
* always use {@code new} to create a new instance.
|
||||
*
|
||||
* @param type the parameterized T represented as a {@link Type}.
|
||||
* @return a default object instance of type T.
|
||||
*/
|
||||
public T createInstance(Type type);
|
||||
}
|
51
src/org/mcteam/factions/gson/JavaFieldNamingPolicy.java
Normal file
51
src/org/mcteam/factions/gson/JavaFieldNamingPolicy.java
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A simple implementation of the {@link FieldNamingStrategy2} interface such that it does not
|
||||
* perform any string translation of the incoming field name.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* JavaFieldNamingPolicy policy = new JavaFieldNamingPolicy();
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("integerField".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* <p>This is the default {@link FieldNamingStrategy2} used by Gson.</p>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JavaFieldNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
||||
return target;
|
||||
}
|
||||
}
|
312
src/org/mcteam/factions/gson/JsonArray.java
Normal file
312
src/org/mcteam/factions/gson/JsonArray.java
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class representing an array type in Json. An array is a list of {@link JsonElement}s each of
|
||||
* which can be of a different type. This is an ordered list, meaning that the order in which
|
||||
* elements are added is preserved.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class JsonArray extends JsonElement implements Iterable<JsonElement> {
|
||||
private final List<JsonElement> elements;
|
||||
|
||||
/**
|
||||
* Creates an empty JsonArray.
|
||||
*/
|
||||
public JsonArray() {
|
||||
elements = new ArrayList<JsonElement>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified element to self.
|
||||
*
|
||||
* @param element the element that needs to be added to the array.
|
||||
*/
|
||||
public void add(JsonElement element) {
|
||||
if (element == null) {
|
||||
element = JsonNull.createJsonNull();
|
||||
}
|
||||
elements.add(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the elements of the specified array to self.
|
||||
*
|
||||
* @param array the array whose elements need to be added to the array.
|
||||
*/
|
||||
public void addAll(JsonArray array) {
|
||||
elements.addAll(array.elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the elements of the array.
|
||||
*/
|
||||
void reverse() {
|
||||
Collections.reverse(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the array.
|
||||
*
|
||||
* @return the number of elements in the array.
|
||||
*/
|
||||
public int size() {
|
||||
return elements.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator to navigate the elemetns of the array. Since the array is an ordered list,
|
||||
* the iterator navigates the elements in the order they were inserted.
|
||||
*
|
||||
* @return an iterator to navigate the elements of the array.
|
||||
*/
|
||||
public Iterator<JsonElement> iterator() {
|
||||
return elements.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ith element of the array.
|
||||
*
|
||||
* @param i the index of the element that is being sought.
|
||||
* @return the element present at the ith index.
|
||||
* @throws IndexOutOfBoundsException if i is negative or greater than or equal to the
|
||||
* {@link #size()} of the array.
|
||||
*/
|
||||
public JsonElement get(int i) {
|
||||
return elements.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a {@link Number} if it contains a single element.
|
||||
*
|
||||
* @return get this element as a number if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid Number.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public Number getAsNumber() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsNumber();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a {@link String} if it contains a single element.
|
||||
*
|
||||
* @return get this element as a String if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid String.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public String getAsString() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsString();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a double if it contains a single element.
|
||||
*
|
||||
* @return get this element as a double if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid double.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public double getAsDouble() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsDouble();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a {@link BigDecimal} if it contains a single element.
|
||||
*
|
||||
* @return get this element as a {@link BigDecimal} if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
|
||||
* @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
* @since 1.2
|
||||
*/
|
||||
@Override
|
||||
public BigDecimal getAsBigDecimal() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsBigDecimal();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a {@link BigInteger} if it contains a single element.
|
||||
*
|
||||
* @return get this element as a {@link BigInteger} if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
|
||||
* @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
* @since 1.2
|
||||
*/
|
||||
@Override
|
||||
public BigInteger getAsBigInteger() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsBigInteger();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a float if it contains a single element.
|
||||
*
|
||||
* @return get this element as a float if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid float.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public float getAsFloat() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsFloat();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a long if it contains a single element.
|
||||
*
|
||||
* @return get this element as a long if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid long.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public long getAsLong() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsLong();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as an integer if it contains a single element.
|
||||
*
|
||||
* @return get this element as an integer if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid integer.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public int getAsInt() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsInt();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getAsByte() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsByte();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getAsCharacter() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsCharacter();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a primitive short if it contains a single element.
|
||||
*
|
||||
* @return get this element as a primitive short if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid short.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public short getAsShort() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsShort();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as a boolean if it contains a single element.
|
||||
*
|
||||
* @return get this element as a boolean if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid boolean.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsBoolean();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this array as an Object if it contains a single element.
|
||||
*
|
||||
* @return get this element as an Object if it is single element array.
|
||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
||||
* is not a valid Object.
|
||||
* @throws IllegalStateException if the array has more than one element.
|
||||
*/
|
||||
@Override
|
||||
Object getAsObject() {
|
||||
if (elements.size() == 1) {
|
||||
return elements.get(0).getAsObject();
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString(Appendable sb, Escaper escaper) throws IOException {
|
||||
sb.append('[');
|
||||
boolean first = true;
|
||||
for (JsonElement element : elements) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
element.toString(sb, escaper);
|
||||
}
|
||||
sb.append(']');
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A visitor that populates fields of an object with data from its equivalent
|
||||
* JSON representation
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
|
||||
|
||||
JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType,
|
||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
super(jsonArray, arrayType, factory, objectConstructor, deserializers, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T constructTarget() {
|
||||
|
||||
TypeInfo typeInfo = new TypeInfo(targetType);
|
||||
|
||||
if (!json.isJsonArray()) {
|
||||
throw new JsonParseException("Expecting array found: " + json);
|
||||
}
|
||||
JsonArray jsonArray = json.getAsJsonArray();
|
||||
if (typeInfo.isArray()) {
|
||||
TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(targetType);
|
||||
// We know that we are getting back an array of the required type, so
|
||||
// this typecasting is safe.
|
||||
return (T) objectConstructor.constructArray(arrayTypeInfo.getSecondLevelType(),
|
||||
jsonArray.size());
|
||||
}
|
||||
// is a collection
|
||||
return (T) objectConstructor.construct(typeInfo.getRawClass());
|
||||
}
|
||||
|
||||
public void visitArray(Object array, Type arrayType) {
|
||||
if (!json.isJsonArray()) {
|
||||
throw new JsonParseException("Expecting array found: " + json);
|
||||
}
|
||||
JsonArray jsonArray = json.getAsJsonArray();
|
||||
TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JsonElement jsonChild = jsonArray.get(i);
|
||||
Object child;
|
||||
|
||||
if (jsonChild == null || jsonChild.isJsonNull()) {
|
||||
child = null;
|
||||
} else if (jsonChild instanceof JsonObject) {
|
||||
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild);
|
||||
} else if (jsonChild instanceof JsonArray) {
|
||||
child = visitChildAsArray(arrayTypeInfo.getSecondLevelType(), jsonChild.getAsJsonArray());
|
||||
} else if (jsonChild instanceof JsonPrimitive) {
|
||||
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(),
|
||||
jsonChild.getAsJsonPrimitive());
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
Array.set(array, i, child);
|
||||
}
|
||||
}
|
||||
|
||||
// We should not implement any other method from Visitor interface since
|
||||
// all other methods should be invoked on JsonObjectDeserializationVisitor
|
||||
// instead.
|
||||
|
||||
public void startVisitingObject(Object node) {
|
||||
throw new JsonParseException("Expecting array but found object: " + node);
|
||||
}
|
||||
|
||||
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
throw new JsonParseException("Expecting array but found array field " + f.getName() + ": "
|
||||
+ obj);
|
||||
}
|
||||
|
||||
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
throw new JsonParseException("Expecting array but found object field " + f.getName() + ": "
|
||||
+ obj);
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, Object parent) {
|
||||
throw new JsonParseException("Expecting array but found field " + f.getName() + ": "
|
||||
+ parent);
|
||||
}
|
||||
|
||||
public void visitPrimitive(Object primitive) {
|
||||
throw new JsonParseException(
|
||||
"Type information is unavailable, and the target is not a primitive: " + json);
|
||||
}
|
||||
}
|
44
src/org/mcteam/factions/gson/JsonDeserializationContext.java
Normal file
44
src/org/mcteam/factions/gson/JsonDeserializationContext.java
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Context for deserialization that is passed to a custom deserializer during invocation of its
|
||||
* {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)}
|
||||
* method.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public interface JsonDeserializationContext {
|
||||
|
||||
/**
|
||||
* Invokes default deserialization on the specified object. It should never be invoked on
|
||||
* the element received as a parameter of the
|
||||
* {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} method. Doing
|
||||
* so will result in an infinite loop since Gson will in-turn call the custom deserializer again.
|
||||
|
||||
* @param json the parse tree.
|
||||
* @param typeOfT type of the expected return value.
|
||||
* @param <T> The type of the deserialized object.
|
||||
* @return An object of type typeOfT.
|
||||
* @throws JsonParseException if the parse tree does not contain expected data.
|
||||
*/
|
||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* implementation of a deserialization context for Gson
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
final class JsonDeserializationContextDefault implements JsonDeserializationContext {
|
||||
|
||||
private final ObjectNavigatorFactory navigatorFactory;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final MappedObjectConstructor objectConstructor;
|
||||
|
||||
JsonDeserializationContextDefault(ObjectNavigatorFactory navigatorFactory,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
MappedObjectConstructor objectConstructor) {
|
||||
this.navigatorFactory = navigatorFactory;
|
||||
this.deserializers = deserializers;
|
||||
this.objectConstructor = objectConstructor;
|
||||
}
|
||||
|
||||
ObjectConstructor getObjectConstructor() {
|
||||
return objectConstructor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
if (json == null || json.isJsonNull()) {
|
||||
return null;
|
||||
} else if (json.isJsonArray()) {
|
||||
return (T) fromJsonArray(typeOfT, json.getAsJsonArray(), this);
|
||||
} else if (json.isJsonObject()) {
|
||||
return (T) fromJsonObject(typeOfT, json.getAsJsonObject(), this);
|
||||
} else if (json.isJsonPrimitive()) {
|
||||
return (T) fromJsonPrimitive(typeOfT, json.getAsJsonPrimitive(), this);
|
||||
} else {
|
||||
throw new JsonParseException("Failed parsing JSON source: " + json + " to Json");
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T fromJsonArray(Type arrayType, JsonArray jsonArray,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonArrayDeserializationVisitor<T> visitor = new JsonArrayDeserializationVisitor<T>(
|
||||
jsonArray, arrayType, navigatorFactory, objectConstructor, deserializers, context);
|
||||
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, arrayType, true));
|
||||
on.accept(visitor);
|
||||
return visitor.getTarget();
|
||||
}
|
||||
|
||||
private <T> T fromJsonObject(Type typeOfT, JsonObject jsonObject,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
||||
jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
|
||||
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, typeOfT, true));
|
||||
on.accept(visitor);
|
||||
return visitor.getTarget();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T fromJsonPrimitive(Type typeOfT, JsonPrimitive json,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
||||
json, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
|
||||
ObjectNavigator on =
|
||||
navigatorFactory.create(new ObjectTypePair(json.getAsObject(), typeOfT, true));
|
||||
on.accept(visitor);
|
||||
Object target = visitor.getTarget();
|
||||
return (T) target;
|
||||
}
|
||||
}
|
112
src/org/mcteam/factions/gson/JsonDeserializationVisitor.java
Normal file
112
src/org/mcteam/factions/gson/JsonDeserializationVisitor.java
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Abstract data value container for the {@link ObjectNavigator.Visitor}
|
||||
* implementations. This class exposes the {@link #getTarget()} method
|
||||
* which returns the class that was visited by this object.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor {
|
||||
|
||||
protected final ObjectNavigatorFactory factory;
|
||||
protected final ObjectConstructor objectConstructor;
|
||||
protected final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
protected T target;
|
||||
protected final JsonElement json;
|
||||
protected final Type targetType;
|
||||
protected final JsonDeserializationContext context;
|
||||
protected boolean constructed;
|
||||
|
||||
public JsonDeserializationVisitor(JsonElement json, Type targetType,
|
||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkNotNull(json);
|
||||
this.targetType = targetType;
|
||||
this.factory = factory;
|
||||
this.objectConstructor = objectConstructor;
|
||||
this.deserializers = deserializers;
|
||||
this.json = json;
|
||||
this.context = context;
|
||||
this.constructed = false;
|
||||
}
|
||||
|
||||
public T getTarget() {
|
||||
if (!constructed) {
|
||||
target = constructTarget();
|
||||
constructed = true;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
protected abstract T constructTarget();
|
||||
|
||||
public void start(ObjectTypePair node) {
|
||||
}
|
||||
|
||||
public void end(ObjectTypePair node) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
Object value = invokeCustomDeserializer(json, pair);
|
||||
target = (T) value;
|
||||
constructed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Object invokeCustomDeserializer(JsonElement element,
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair) {
|
||||
if (element == null || element.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
Type objType = pair.second.type;
|
||||
return (pair.first).deserialize(element, objType, context);
|
||||
}
|
||||
|
||||
final Object visitChildAsObject(Type childType, JsonElement jsonChild) {
|
||||
JsonDeserializationVisitor<?> childVisitor =
|
||||
new JsonObjectDeserializationVisitor<Object>(jsonChild, childType,
|
||||
factory, objectConstructor, deserializers, context);
|
||||
return visitChild(childType, childVisitor);
|
||||
}
|
||||
|
||||
final Object visitChildAsArray(Type childType, JsonArray jsonChild) {
|
||||
JsonDeserializationVisitor<?> childVisitor =
|
||||
new JsonArrayDeserializationVisitor<Object>(jsonChild.getAsJsonArray(), childType,
|
||||
factory, objectConstructor, deserializers, context);
|
||||
return visitChild(childType, childVisitor);
|
||||
}
|
||||
|
||||
private Object visitChild(Type type, JsonDeserializationVisitor<?> childVisitor) {
|
||||
ObjectNavigator on = factory.create(new ObjectTypePair(null, type, false));
|
||||
on.accept(childVisitor);
|
||||
// the underlying object may have changed during the construction phase
|
||||
// This happens primarily because of custom deserializers
|
||||
return childVisitor.getTarget();
|
||||
}
|
||||
}
|
88
src/org/mcteam/factions/gson/JsonDeserializer.java
Normal file
88
src/org/mcteam/factions/gson/JsonDeserializer.java
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* <p>Interface representing a custom deserializer for Json. You should write a custom
|
||||
* deserializer, if you are not happy with the default deserialization done by Gson. You will
|
||||
* also need to register this deserializer through
|
||||
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}.</p>
|
||||
*
|
||||
* <p>Let us look at example where defining a deserializer will be useful. The {@code Id} class
|
||||
* defined below has two fields: {@code clazz} and {@code value}.</p>
|
||||
*
|
||||
* <pre>
|
||||
* public class Id<T> {
|
||||
* private final Class<T> clazz;
|
||||
* private final long value;
|
||||
* public Id(Class<T> clazz, long value) {
|
||||
* this.clazz = clazz;
|
||||
* this.value = value;
|
||||
* }
|
||||
* public long getValue() {
|
||||
* return value;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the
|
||||
* Json string to be <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you already know
|
||||
* the type of the field that the {@code Id} will be deserialized into, and hence just want to
|
||||
* deserialize it from a Json string {@code 20}. You can achieve that by writing a custom
|
||||
* deserializer:</p>
|
||||
*
|
||||
* <pre>
|
||||
* class IdDeserializer implements JsonDeserializer<Id>() {
|
||||
* public Id fromJson(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
* throws JsonParseException {
|
||||
* return (Id) new Id((Class)typeOfT, id.getValue());
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>You will also need to register {@code IdDeserializer} with Gson as follows:</p>
|
||||
*
|
||||
* <pre>
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdDeserializer()).create();
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @param <T> type for which the deserializer is being registered. It is possible that a
|
||||
* deserializer may be asked to deserialize a specific generic type of the T.
|
||||
*/
|
||||
public interface JsonDeserializer<T> {
|
||||
|
||||
/**
|
||||
* Gson invokes this call-back method during deserialization when it encounters a field of the
|
||||
* specified type.
|
||||
* <p>In the implementation of this call-back method, you should consider invoking
|
||||
* {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects
|
||||
* for any non-trivial field of the returned object. However, you should never invoke it on the
|
||||
* the same type passing {@code json} since that will cause an infinite loop (Gson will call your
|
||||
* call-back method again).
|
||||
*
|
||||
* @param json The Json data being deserialized
|
||||
* @param typeOfT The type of the Object to deserialize to
|
||||
* @return a deserialized object of the specified type typeOfT which is a subclass of {@code T}
|
||||
* @throws JsonParseException if json is not in the expected format of {@code typeofT}
|
||||
*/
|
||||
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Decorators a {@code JsonDeserializer} instance with exception handling. This wrapper class
|
||||
* ensures that a {@code JsonDeserializer} will not propagate any exception other than a
|
||||
* {@link JsonParseException}.
|
||||
*
|
||||
* @param <T> type of the deserializer being wrapped.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
|
||||
|
||||
private final JsonDeserializer<T> delegate;
|
||||
|
||||
/**
|
||||
* Returns a wrapped {@link JsonDeserializer} object that has been decorated with
|
||||
* {@link JsonParseException} handling.
|
||||
*
|
||||
* @param delegate the {@code JsonDeserializer} instance to be wrapped.
|
||||
* @throws IllegalArgumentException if {@code delegate} is {@code null}.
|
||||
*/
|
||||
JsonDeserializerExceptionWrapper(JsonDeserializer<T> delegate) {
|
||||
Preconditions.checkNotNull(delegate);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
try {
|
||||
return delegate.deserialize(json, typeOfT, context);
|
||||
} catch (JsonParseException e) {
|
||||
// just rethrow the exception
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// rethrow as a JsonParseException
|
||||
StringBuilder errorMsg = new StringBuilder()
|
||||
.append("The JsonDeserializer ")
|
||||
.append(delegate)
|
||||
.append(" failed to deserialized json object ")
|
||||
.append(json)
|
||||
.append(" given the type ")
|
||||
.append(typeOfT);
|
||||
throw new JsonParseException(errorMsg.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
}
|
338
src/org/mcteam/factions/gson/JsonElement.java
Normal file
338
src/org/mcteam/factions/gson/JsonElement.java
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* A class representing an element of Json. It could either be a {@link JsonObject}, a
|
||||
* {@link JsonArray}, a {@link JsonPrimitive} or a {@link JsonNull}.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public abstract class JsonElement {
|
||||
private static final Escaper BASIC_ESCAPER = new Escaper(false);
|
||||
|
||||
/**
|
||||
* provides check for verifying if this element is an array or not.
|
||||
*
|
||||
* @return true if this element is of type {@link JsonArray}, false otherwise.
|
||||
*/
|
||||
public boolean isJsonArray() {
|
||||
return this instanceof JsonArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* provides check for verifying if this element is a Json object or not.
|
||||
*
|
||||
* @return true if this element is of type {@link JsonObject}, false otherwise.
|
||||
*/
|
||||
public boolean isJsonObject() {
|
||||
return this instanceof JsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* provides check for verifying if this element is a primitive or not.
|
||||
*
|
||||
* @return true if this element is of type {@link JsonPrimitive}, false otherwise.
|
||||
*/
|
||||
public boolean isJsonPrimitive() {
|
||||
return this instanceof JsonPrimitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* provides check for verifying if this element represents a null value or not.
|
||||
*
|
||||
* @return true if this element is of type {@link JsonNull}, false otherwise.
|
||||
* @since 1.2
|
||||
*/
|
||||
public boolean isJsonNull() {
|
||||
return this instanceof JsonNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link JsonObject}. If the element is of some
|
||||
* other type, a {@link ClassCastException} will result. Hence it is best to use this method
|
||||
* after ensuring that this element is of the desired type by calling {@link #isJsonObject()}
|
||||
* first.
|
||||
*
|
||||
* @return get this element as a {@link JsonObject}.
|
||||
* @throws IllegalStateException if the element is of another type.
|
||||
*/
|
||||
public JsonObject getAsJsonObject() {
|
||||
if (isJsonObject()) {
|
||||
return (JsonObject) this;
|
||||
}
|
||||
throw new IllegalStateException("This is not a JSON Object.");
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link JsonArray}. If the element is of some
|
||||
* other type, a {@link ClassCastException} will result. Hence it is best to use this method
|
||||
* after ensuring that this element is of the desired type by calling {@link #isJsonArray()}
|
||||
* first.
|
||||
*
|
||||
* @return get this element as a {@link JsonArray}.
|
||||
* @throws IllegalStateException if the element is of another type.
|
||||
*/
|
||||
public JsonArray getAsJsonArray() {
|
||||
if (isJsonArray()) {
|
||||
return (JsonArray) this;
|
||||
}
|
||||
throw new IllegalStateException("This is not a JSON Array.");
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link JsonPrimitive}. If the element is of some
|
||||
* other type, a {@link ClassCastException} will result. Hence it is best to use this method
|
||||
* after ensuring that this element is of the desired type by calling {@link #isJsonPrimitive()}
|
||||
* first.
|
||||
*
|
||||
* @return get this element as a {@link JsonPrimitive}.
|
||||
* @throws IllegalStateException if the element is of another type.
|
||||
*/
|
||||
public JsonPrimitive getAsJsonPrimitive() {
|
||||
if (isJsonPrimitive()) {
|
||||
return (JsonPrimitive) this;
|
||||
}
|
||||
throw new IllegalStateException("This is not a JSON Primitive.");
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link JsonNull}. If the element is of some
|
||||
* other type, a {@link ClassCastException} will result. Hence it is best to use this method
|
||||
* after ensuring that this element is of the desired type by calling {@link #isJsonNull()}
|
||||
* first.
|
||||
*
|
||||
* @return get this element as a {@link JsonNull}.
|
||||
* @throws IllegalStateException if the element is of another type.
|
||||
* @since 1.2
|
||||
*/
|
||||
public JsonNull getAsJsonNull() {
|
||||
if (isJsonNull()) {
|
||||
return (JsonNull) this;
|
||||
}
|
||||
throw new IllegalStateException("This is not a JSON Null.");
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a boolean value.
|
||||
*
|
||||
* @return get this element as a primitive boolean value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* boolean value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public boolean getAsBoolean() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link Boolean} value.
|
||||
*
|
||||
* @return get this element as a {@link Boolean} value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* boolean value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
Boolean getAsBooleanWrapper() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link Number}.
|
||||
*
|
||||
* @return get this element as a {@link Number}.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* number.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public Number getAsNumber() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a string value.
|
||||
*
|
||||
* @return get this element as a string value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* string value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public String getAsString() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive double value.
|
||||
*
|
||||
* @return get this element as a primitive double value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* double value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public double getAsDouble() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive float value.
|
||||
*
|
||||
* @return get this element as a primitive float value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* float value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public float getAsFloat() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive long value.
|
||||
*
|
||||
* @return get this element as a primitive long value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* long value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public long getAsLong() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive integer value.
|
||||
*
|
||||
* @return get this element as a primitive integer value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* integer value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public int getAsInt() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive byte value.
|
||||
*
|
||||
* @return get this element as a primitive byte value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* byte value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
* @since 1.3
|
||||
*/
|
||||
public byte getAsByte() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive character value.
|
||||
*
|
||||
* @return get this element as a primitive char value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* char value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
* @since 1.3
|
||||
*/
|
||||
public char getAsCharacter() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link BigDecimal}.
|
||||
*
|
||||
* @return get this element as a {@link BigDecimal}.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive}.
|
||||
* * @throws NumberFormatException if the element is not a valid {@link BigDecimal}.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
* @since 1.2
|
||||
*/
|
||||
public BigDecimal getAsBigDecimal() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link BigInteger}.
|
||||
*
|
||||
* @return get this element as a {@link BigInteger}.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive}.
|
||||
* @throws NumberFormatException if the element is not a valid {@link BigInteger}.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
* @since 1.2
|
||||
*/
|
||||
public BigInteger getAsBigInteger() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive short value.
|
||||
*
|
||||
* @return get this element as a primitive short value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* short value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
public short getAsShort() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as an {@link Object} value.
|
||||
*
|
||||
* @return get this element as an Object value.
|
||||
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
|
||||
* Object value.
|
||||
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
|
||||
* more than a single element.
|
||||
*/
|
||||
Object getAsObject() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representation of this element.
|
||||
*
|
||||
* @return String the string representation of this element.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toString(sb, BASIC_ESCAPER);
|
||||
return sb.toString();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void toString(Appendable sb, Escaper escaper) throws IOException;
|
||||
}
|
47
src/org/mcteam/factions/gson/JsonElementVisitor.java
Normal file
47
src/org/mcteam/factions/gson/JsonElementVisitor.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Definition of a visitor for a JsonElement tree.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
interface JsonElementVisitor {
|
||||
void visitPrimitive(JsonPrimitive primitive) throws IOException;
|
||||
void visitNull() throws IOException;
|
||||
|
||||
void startArray(JsonArray array) throws IOException;
|
||||
void visitArrayMember(JsonArray parent, JsonPrimitive member, boolean isFirst) throws IOException;
|
||||
void visitArrayMember(JsonArray parent, JsonArray member, boolean isFirst) throws IOException;
|
||||
void visitArrayMember(JsonArray parent, JsonObject member, boolean isFirst) throws IOException;
|
||||
void visitNullArrayMember(JsonArray parent, boolean isFirst) throws IOException;
|
||||
void endArray(JsonArray array) throws IOException;
|
||||
|
||||
void startObject(JsonObject object) throws IOException;
|
||||
void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member,
|
||||
boolean isFirst) throws IOException;
|
||||
void visitObjectMember(JsonObject parent, String memberName, JsonArray member,
|
||||
boolean isFirst) throws IOException;
|
||||
void visitObjectMember(JsonObject parent, String memberName, JsonObject member,
|
||||
boolean isFirst) throws IOException;
|
||||
void visitNullObjectMember(JsonObject parent, String memberName,
|
||||
boolean isFirst) throws IOException;
|
||||
void endObject(JsonObject object) throws IOException;
|
||||
}
|
56
src/org/mcteam/factions/gson/JsonFieldNameValidator.java
Normal file
56
src/org/mcteam/factions/gson/JsonFieldNameValidator.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* This class can be used to check the validity of a JSON field name.
|
||||
*
|
||||
* <p>The primary use of this object is to ensure that any Java fields that use the
|
||||
* {@link org.mcteam.factions.gson.annotations.SerializedName} annotation is providing valid JSON
|
||||
* field names. This will make the code fail-fast rather than letting the invalid
|
||||
* field name propagate to the client and it fails to parse.</p>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
class JsonFieldNameValidator {
|
||||
private static final String COMMON_PATTERN = "[a-zA-Z][a-zA-Z0-9\\ \\$_\\-]*$";
|
||||
|
||||
private static final Pattern JSON_FIELD_NAME_PATTERN =
|
||||
Pattern.compile("(^" + COMMON_PATTERN + ")|(^[\\$_]" + COMMON_PATTERN + ")");
|
||||
|
||||
|
||||
/**
|
||||
* Performs validation on the JSON field name to ensure it is a valid field name.
|
||||
*
|
||||
* @param fieldName the name of the field to validate
|
||||
* @return {@code fieldName} if it is a valid JSON field name
|
||||
* @throws IllegalArgumentException if the field name is an invalid JSON field name
|
||||
*/
|
||||
public String validate(String fieldName) {
|
||||
Preconditions.checkNotNull(fieldName);
|
||||
Preconditions.checkArgument(!"".equals(fieldName.trim()));
|
||||
|
||||
Matcher matcher = JSON_FIELD_NAME_PATTERN.matcher(fieldName);
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException(fieldName + " is not a valid JSON field name.");
|
||||
}
|
||||
return fieldName;
|
||||
}
|
||||
}
|
46
src/org/mcteam/factions/gson/JsonIOException.java
Normal file
46
src/org/mcteam/factions/gson/JsonIOException.java
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* This exception is raised when Gson was unable to read an input stream
|
||||
* or write to one.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class JsonIOException extends JsonParseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JsonIOException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public JsonIOException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates exception with the specified cause. Consider using
|
||||
* {@link #JsonIOException(String, Throwable)} instead if you can describe what happened.
|
||||
*
|
||||
* @param cause root exception that caused this exception to be thrown.
|
||||
*/
|
||||
public JsonIOException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
72
src/org/mcteam/factions/gson/JsonNull.java
Normal file
72
src/org/mcteam/factions/gson/JsonNull.java
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A class representing a Json {@code null} value.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @since 1.2
|
||||
*/
|
||||
public final class JsonNull extends JsonElement {
|
||||
private static final JsonNull INSTANCE = new JsonNull();
|
||||
|
||||
/**
|
||||
* Creates a new JsonNull object.
|
||||
*/
|
||||
public JsonNull() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString(Appendable sb, Escaper escaper) throws IOException {
|
||||
sb.append("null");
|
||||
}
|
||||
|
||||
/**
|
||||
* All instances of JsonNull have the same hash code since they are indistinguishable
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return JsonNull.class.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* All instances of JsonNull are the same
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof JsonNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creation method used to return an instance of a {@link JsonNull}. To reduce the memory
|
||||
* footprint, a single object has been created for this class; therefore the same instance is
|
||||
* being returned for each invocation of this method. This method is kept private since we
|
||||
* prefer the users to use {@link JsonNull#JsonNull()} which is similar to how other JsonElements
|
||||
* are created. Note that all instances of JsonNull return true for {@link #equals(Object)}
|
||||
* when compared to each other.
|
||||
*
|
||||
* @return a instance of a {@link JsonNull}
|
||||
*/
|
||||
static JsonNull createJsonNull() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
208
src/org/mcteam/factions/gson/JsonObject.java
Normal file
208
src/org/mcteam/factions/gson/JsonObject.java
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A class representing an object type in Json. An object consists of name-value pairs where names
|
||||
* are strings, and values are any other type of {@link JsonElement}. This allows for a creating a
|
||||
* tree of JsonElements. The member elements of this object are maintained in order they were added.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class JsonObject extends JsonElement {
|
||||
// We are using a linked hash map because it is important to preserve
|
||||
// the order in which elements are inserted. This is needed to ensure
|
||||
// that the fields of an object are inserted in the order they were
|
||||
// defined in the class.
|
||||
private final Map<String, JsonElement> members;
|
||||
|
||||
/**
|
||||
* Creates an empty JsonObject.
|
||||
*/
|
||||
public JsonObject() {
|
||||
members = new LinkedHashMap<String, JsonElement>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a member, which is a name-value pair, to self. The name must be a String, but the value
|
||||
* can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements
|
||||
* rooted at this node.
|
||||
*
|
||||
* @param property name of the member.
|
||||
* @param value the member object.
|
||||
*/
|
||||
public void add(String property, JsonElement value) {
|
||||
Preconditions.checkNotNull(property);
|
||||
if (value == null) {
|
||||
value = JsonNull.createJsonNull();
|
||||
}
|
||||
members.put(property, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the {@code property} from this {@link JsonObject}.
|
||||
*
|
||||
* @param property name of the member that should be removed.
|
||||
* @return the {@link JsonElement} object that is being removed.
|
||||
* @since 1.3
|
||||
*/
|
||||
public JsonElement remove(String property) {
|
||||
return members.remove(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a primitive member. The specified value is converted to a
|
||||
* JsonPrimitive of String.
|
||||
*
|
||||
* @param property name of the member.
|
||||
* @param value the string value associated with the member.
|
||||
*/
|
||||
public void addProperty(String property, String value) {
|
||||
add(property, createJsonElement(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a primitive member. The specified value is converted to a
|
||||
* JsonPrimitive of Number.
|
||||
*
|
||||
* @param property name of the member.
|
||||
* @param value the number value associated with the member.
|
||||
*/
|
||||
public void addProperty(String property, Number value) {
|
||||
add(property, createJsonElement(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a boolean member. The specified value is converted to a
|
||||
* JsonPrimitive of Boolean.
|
||||
*
|
||||
* @param property name of the member.
|
||||
* @param value the number value associated with the member.
|
||||
*/
|
||||
public void addProperty(String property, Boolean value) {
|
||||
add(property, createJsonElement(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a char member. The specified value is converted to a
|
||||
* JsonPrimitive of Character.
|
||||
*
|
||||
* @param property name of the member.
|
||||
* @param value the number value associated with the member.
|
||||
*/
|
||||
public void addProperty(String property, Character value) {
|
||||
add(property, createJsonElement(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper {@link JsonElement} object from the given {@code value} object.
|
||||
*
|
||||
* @param value the object to generate the {@link JsonElement} for
|
||||
* @return a {@link JsonPrimitive} if the {@code value} is not null, otherwise a {@link JsonNull}
|
||||
*/
|
||||
private JsonElement createJsonElement(Object value) {
|
||||
return value == null ? JsonNull.createJsonNull() : new JsonPrimitive(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of members of this object. The set is ordered, and the order is in which the
|
||||
* elements were added.
|
||||
*
|
||||
* @return a set of members of this object.
|
||||
*/
|
||||
public Set<Map.Entry<String, JsonElement>> entrySet() {
|
||||
return members.entrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to check if a member with the specified name is present in this object.
|
||||
*
|
||||
* @param memberName name of the member that is being checked for presence.
|
||||
* @return true if there is a member with the specified name, false otherwise.
|
||||
*/
|
||||
public boolean has(String memberName) {
|
||||
return members.containsKey(memberName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the member with the specified name.
|
||||
*
|
||||
* @param memberName name of the member that is being requested.
|
||||
* @return the member matching the name. Null if no such member exists.
|
||||
*/
|
||||
public JsonElement get(String memberName) {
|
||||
if (members.containsKey(memberName)) {
|
||||
JsonElement member = members.get(memberName);
|
||||
return member == null ? JsonNull.createJsonNull() : member;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get the specified member as a JsonPrimitive element.
|
||||
*
|
||||
* @param memberName name of the member being requested.
|
||||
* @return the JsonPrimitive corresponding to the specified member.
|
||||
*/
|
||||
public JsonPrimitive getAsJsonPrimitive(String memberName) {
|
||||
return (JsonPrimitive) members.get(memberName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get the specified member as a JsonArray.
|
||||
*
|
||||
* @param memberName name of the member being requested.
|
||||
* @return the JsonArray corresponding to the specified member.
|
||||
*/
|
||||
public JsonArray getAsJsonArray(String memberName) {
|
||||
return (JsonArray) members.get(memberName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to get the specified member as a JsonObject.
|
||||
*
|
||||
* @param memberName name of the member being requested.
|
||||
* @return the JsonObject corresponding to the specified member.
|
||||
*/
|
||||
public JsonObject getAsJsonObject(String memberName) {
|
||||
return (JsonObject) members.get(memberName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString(Appendable sb, Escaper escaper) throws IOException {
|
||||
sb.append('{');
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, JsonElement> entry : members.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append('\"');
|
||||
sb.append(escaper.escapeJsonString(entry.getKey()));
|
||||
sb.append("\":");
|
||||
entry.getValue().toString(sb, escaper);
|
||||
}
|
||||
sb.append('}');
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A visitor that populates fields of an object with data from its equivalent
|
||||
* JSON representation
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
|
||||
|
||||
JsonObjectDeserializationVisitor(JsonElement json, Type type,
|
||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
super(json, type, factory, objectConstructor, deserializers, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T constructTarget() {
|
||||
return (T) objectConstructor.construct(targetType);
|
||||
}
|
||||
|
||||
public void startVisitingObject(Object node) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void visitArray(Object array, Type componentType) {
|
||||
// should not be called since this case should invoke JsonArrayDeserializationVisitor
|
||||
throw new JsonParseException("Expecting object but found array: " + array);
|
||||
}
|
||||
|
||||
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (!json.isJsonObject()) {
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
String fName = getFieldName(f);
|
||||
JsonElement jsonChild = jsonObject.get(fName);
|
||||
if (jsonChild != null) {
|
||||
Object child = visitChildAsObject(typeOfF, jsonChild);
|
||||
f.set(obj, child);
|
||||
} else {
|
||||
f.set(obj, null);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (!json.isJsonObject()) {
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
String fName = getFieldName(f);
|
||||
JsonArray jsonChild = (JsonArray) jsonObject.get(fName);
|
||||
if (jsonChild != null) {
|
||||
Object array = visitChildAsArray(typeOfF, jsonChild);
|
||||
f.set(obj, array);
|
||||
} else {
|
||||
f.set(obj, null);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFieldName(FieldAttributes f) {
|
||||
FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
|
||||
return namingPolicy.translateName(f);
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
|
||||
try {
|
||||
String fName = getFieldName(f);
|
||||
if (!json.isJsonObject()) {
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonElement child = json.getAsJsonObject().get(fName);
|
||||
TypeInfo typeInfo = new TypeInfo(declaredTypeOfField);
|
||||
if (child == null) { // Child will be null if the field wasn't present in Json
|
||||
return true;
|
||||
} else if (child.isJsonNull()) {
|
||||
if (!typeInfo.isPrimitive()) {
|
||||
f.set(parent, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ObjectTypePair objTypePair = new ObjectTypePair(null, declaredTypeOfField, false);
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
Object value = invokeCustomDeserializer(child, pair);
|
||||
if (value != null || !typeInfo.isPrimitive()) {
|
||||
f.set(parent, value);
|
||||
}
|
||||
return true;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void visitPrimitive(Object primitive) {
|
||||
if (!json.isJsonPrimitive()) {
|
||||
throw new JsonParseException(
|
||||
"Type information is unavailable, and the target object is not a primitive: " + json);
|
||||
}
|
||||
JsonPrimitive prim = json.getAsJsonPrimitive();
|
||||
target = (T) prim.getAsObject();
|
||||
}
|
||||
}
|
64
src/org/mcteam/factions/gson/JsonParseException.java
Normal file
64
src/org/mcteam/factions/gson/JsonParseException.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* This exception is raised if there is a serious issue that occurs during parsing of a Json
|
||||
* string. One of the main usages for this class is for the Gson infrastructure. If the incoming
|
||||
* Json is bad/malicious, an instance of this exception is raised.
|
||||
*
|
||||
* <p>This exception is a {@link RuntimeException} because it is exposed to the client. Using a
|
||||
* {@link RuntimeException} avoids bad coding practices on the client side where they catch the
|
||||
* exception and do nothing. It is often the case that you want to blow up if there is a parsing
|
||||
* error (i.e. often clients do not know how to recover from a {@link JsonParseException}.</p>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class JsonParseException extends RuntimeException {
|
||||
static final long serialVersionUID = -4086729973971783390L;
|
||||
|
||||
/**
|
||||
* Creates exception with the specified message. If you are wrapping another exception, consider
|
||||
* using {@link #JsonParseException(String, Throwable)} instead.
|
||||
*
|
||||
* @param msg error message describing a possible cause of this exception.
|
||||
*/
|
||||
public JsonParseException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates exception with the specified message and cause.
|
||||
*
|
||||
* @param msg error message describing what happened.
|
||||
* @param cause root exception that caused this exception to be thrown.
|
||||
*/
|
||||
public JsonParseException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates exception with the specified cause. Consider using
|
||||
* {@link #JsonParseException(String, Throwable)} instead if you can describe what happened.
|
||||
*
|
||||
* @param cause root exception that caused this exception to be thrown.
|
||||
*/
|
||||
public JsonParseException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
98
src/org/mcteam/factions/gson/JsonParser.java
Normal file
98
src/org/mcteam/factions/gson/JsonParser.java
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonToken;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
|
||||
/**
|
||||
* A parser to parse Json into a parse tree of {@link JsonElement}s
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @since 1.3
|
||||
*/
|
||||
public final class JsonParser {
|
||||
|
||||
/**
|
||||
* Parses the specified JSON string into a parse tree
|
||||
*
|
||||
* @param json JSON text
|
||||
* @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
|
||||
* @throws JsonParseException if the specified text is not valid JSON
|
||||
* @since 1.3
|
||||
*/
|
||||
public JsonElement parse(String json) throws JsonSyntaxException {
|
||||
return parse(new StringReader(json));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the specified JSON string into a parse tree
|
||||
*
|
||||
* @param json JSON text
|
||||
* @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
|
||||
* @throws JsonParseException if the specified text is not valid JSON
|
||||
* @since 1.3
|
||||
*/
|
||||
public JsonElement parse(Reader json) throws JsonIOException, JsonSyntaxException {
|
||||
try {
|
||||
JsonReader jsonReader = new JsonReader(json);
|
||||
JsonElement element = parse(jsonReader);
|
||||
if (!element.isJsonNull() && jsonReader.peek() != JsonToken.END_DOCUMENT) {
|
||||
throw new JsonSyntaxException("Did not consume the entire document.");
|
||||
}
|
||||
return element;
|
||||
} catch (MalformedJsonException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next value from the JSON stream as a parse tree.
|
||||
*
|
||||
* @throws JsonParseException if there is an IOException or if the specified
|
||||
* text is not valid JSON
|
||||
* @since 1.6
|
||||
*/
|
||||
public JsonElement parse(JsonReader json) throws JsonIOException, JsonSyntaxException {
|
||||
boolean lenient = json.isLenient();
|
||||
json.setLenient(true);
|
||||
try {
|
||||
return Streams.parse(json);
|
||||
} catch (StackOverflowError e) {
|
||||
throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
|
||||
} catch (JsonParseException e) {
|
||||
if (e.getCause() instanceof EOFException) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
json.setLenient(lenient);
|
||||
}
|
||||
}
|
||||
}
|
387
src/org/mcteam/factions/gson/JsonPrimitive.java
Normal file
387
src/org/mcteam/factions/gson/JsonPrimitive.java
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* A class representing a Json primitive value. A primitive value
|
||||
* is either a String, a Java primitive, or a Java primitive
|
||||
* wrapper type.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class JsonPrimitive extends JsonElement {
|
||||
private static final Class<?>[] PRIMITIVE_TYPES = { int.class, long.class, short.class,
|
||||
float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class,
|
||||
Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };
|
||||
|
||||
private static final BigInteger INTEGER_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
|
||||
private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
|
||||
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Create a primitive containing a boolean value.
|
||||
*
|
||||
* @param bool the value to create the primitive with.
|
||||
*/
|
||||
public JsonPrimitive(Boolean bool) {
|
||||
setValue(bool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a primitive containing a {@link Number}.
|
||||
*
|
||||
* @param number the value to create the primitive with.
|
||||
*/
|
||||
public JsonPrimitive(Number number) {
|
||||
setValue(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a primitive containing a String value.
|
||||
*
|
||||
* @param string the value to create the primitive with.
|
||||
*/
|
||||
public JsonPrimitive(String string) {
|
||||
setValue(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a primitive containing a character. The character is turned into a one character String
|
||||
* since Json only supports String.
|
||||
*
|
||||
* @param c the value to create the primitive with.
|
||||
*/
|
||||
public JsonPrimitive(Character c) {
|
||||
setValue(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a primitive using the specified Object. It must be an instance of {@link Number}, a
|
||||
* Java primitive type, or a String.
|
||||
*
|
||||
* @param primitive the value to create the primitive with.
|
||||
*/
|
||||
JsonPrimitive(Object primitive) {
|
||||
setValue(primitive);
|
||||
}
|
||||
|
||||
void setValue(Object primitive) {
|
||||
if (primitive instanceof Character) {
|
||||
// convert characters to strings since in JSON, characters are represented as a single
|
||||
// character string
|
||||
char c = ((Character) primitive).charValue();
|
||||
this.value = String.valueOf(c);
|
||||
} else {
|
||||
Preconditions.checkArgument(primitive instanceof Number
|
||||
|| isPrimitiveOrString(primitive));
|
||||
this.value = primitive;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this primitive contains a boolean value.
|
||||
*
|
||||
* @return true if this primitive contains a boolean value, false otherwise.
|
||||
*/
|
||||
public boolean isBoolean() {
|
||||
return value instanceof Boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link Boolean}.
|
||||
*
|
||||
* @return get this element as a {@link Boolean}.
|
||||
* @throws ClassCastException if the value contained is not a valid boolean value.
|
||||
*/
|
||||
@Override
|
||||
Boolean getAsBooleanWrapper() {
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a boolean value.
|
||||
*
|
||||
* @return get this element as a primitive boolean value.
|
||||
* @throws ClassCastException if the value contained is not a valid boolean value.
|
||||
*/
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
return isBoolean() ? getAsBooleanWrapper().booleanValue() : Boolean.parseBoolean(getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this primitive contains a Number.
|
||||
*
|
||||
* @return true if this primitive contains a Number, false otherwise.
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
return value instanceof Number;
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a Number.
|
||||
*
|
||||
* @return get this element as a Number.
|
||||
* @throws ClassCastException if the value contained is not a valid Number.
|
||||
*/
|
||||
@Override
|
||||
public Number getAsNumber() {
|
||||
return value instanceof String ? stringToNumber((String) value) : (Number) value;
|
||||
}
|
||||
|
||||
static Number stringToNumber(String value) {
|
||||
try {
|
||||
long longValue = Long.parseLong(value);
|
||||
if (longValue >= Integer.MIN_VALUE && longValue <= Integer.MAX_VALUE) {
|
||||
return (int) longValue;
|
||||
}
|
||||
return longValue;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
return new BigDecimal(value);
|
||||
} catch (NumberFormatException ignored) {
|
||||
return Double.parseDouble(value); // probably NaN, -Infinity or Infinity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this primitive contains a String value.
|
||||
*
|
||||
* @return true if this primitive contains a String value, false otherwise.
|
||||
*/
|
||||
public boolean isString() {
|
||||
return value instanceof String;
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a String.
|
||||
*
|
||||
* @return get this element as a String.
|
||||
* @throws ClassCastException if the value contained is not a valid String.
|
||||
*/
|
||||
@Override
|
||||
public String getAsString() {
|
||||
if (isNumber()) {
|
||||
return getAsNumber().toString();
|
||||
} else if (isBoolean()) {
|
||||
return getAsBooleanWrapper().toString();
|
||||
} else {
|
||||
return (String) value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive double.
|
||||
*
|
||||
* @return get this element as a primitive double.
|
||||
* @throws ClassCastException if the value contained is not a valid double.
|
||||
*/
|
||||
@Override
|
||||
public double getAsDouble() {
|
||||
return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link BigDecimal}.
|
||||
*
|
||||
* @return get this element as a {@link BigDecimal}.
|
||||
* @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}.
|
||||
*/
|
||||
@Override
|
||||
public BigDecimal getAsBigDecimal() {
|
||||
return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a {@link BigInteger}.
|
||||
*
|
||||
* @return get this element as a {@link BigInteger}.
|
||||
* @throws NumberFormatException if the value contained is not a valid {@link BigInteger}.
|
||||
*/
|
||||
@Override
|
||||
public BigInteger getAsBigInteger() {
|
||||
return value instanceof BigInteger ? (BigInteger) value : new BigInteger(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a float.
|
||||
*
|
||||
* @return get this element as a float.
|
||||
* @throws ClassCastException if the value contained is not a valid float.
|
||||
*/
|
||||
@Override
|
||||
public float getAsFloat() {
|
||||
return isNumber() ? getAsNumber().floatValue() : Float.parseFloat(getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive long.
|
||||
*
|
||||
* @return get this element as a primitive long.
|
||||
* @throws ClassCastException if the value contained is not a valid long.
|
||||
*/
|
||||
@Override
|
||||
public long getAsLong() {
|
||||
return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive short.
|
||||
*
|
||||
* @return get this element as a primitive short.
|
||||
* @throws ClassCastException if the value contained is not a valid short value.
|
||||
*/
|
||||
@Override
|
||||
public short getAsShort() {
|
||||
return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString());
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as a primitive integer.
|
||||
*
|
||||
* @return get this element as a primitive integer.
|
||||
* @throws ClassCastException if the value contained is not a valid integer.
|
||||
*/
|
||||
@Override
|
||||
public int getAsInt() {
|
||||
return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getAsByte() {
|
||||
return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getAsCharacter() {
|
||||
return getAsString().charAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* convenience method to get this element as an Object.
|
||||
*
|
||||
* @return get this element as an Object that can be converted to a suitable value.
|
||||
*/
|
||||
@Override
|
||||
Object getAsObject() {
|
||||
if (value instanceof BigInteger) {
|
||||
BigInteger big = (BigInteger) value;
|
||||
if (big.compareTo(INTEGER_MAX) < 0) {
|
||||
return big.intValue();
|
||||
} else if (big.compareTo(LONG_MAX) < 0) {
|
||||
return big.longValue();
|
||||
}
|
||||
}
|
||||
// No need to convert to float or double since those lose precision
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString(Appendable sb, Escaper escaper) throws IOException {
|
||||
if (isString()) {
|
||||
sb.append('"');
|
||||
sb.append(escaper.escapeJsonString(value.toString()));
|
||||
sb.append('"');
|
||||
} else {
|
||||
sb.append(value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPrimitiveOrString(Object target) {
|
||||
if (target instanceof String) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<?> classOfPrimitive = target.getClass();
|
||||
for (Class<?> standardPrimitive : PRIMITIVE_TYPES) {
|
||||
if (standardPrimitive.isAssignableFrom(classOfPrimitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (value == null) {
|
||||
return 31;
|
||||
}
|
||||
// Using recommended hashing algorithm from Effective Java for longs and doubles
|
||||
if (isIntegral(this)) {
|
||||
long value = getAsNumber().longValue();
|
||||
return (int) (value ^ (value >>> 32));
|
||||
}
|
||||
if (isFloatingPoint(this)) {
|
||||
long value = Double.doubleToLongBits(getAsNumber().doubleValue());
|
||||
return (int) (value ^ (value >>> 32));
|
||||
}
|
||||
return value.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
JsonPrimitive other = (JsonPrimitive)obj;
|
||||
if (value == null) {
|
||||
return other.value == null;
|
||||
}
|
||||
if (isIntegral(this) && isIntegral(other)) {
|
||||
return getAsNumber().longValue() == other.getAsNumber().longValue();
|
||||
}
|
||||
if (isFloatingPoint(this) && isFloatingPoint(other)) {
|
||||
return getAsNumber().doubleValue() == other.getAsNumber().doubleValue();
|
||||
}
|
||||
return value.equals(other.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified number is an integral type
|
||||
* (Long, Integer, Short, Byte, BigInteger)
|
||||
*/
|
||||
private static boolean isIntegral(JsonPrimitive primitive) {
|
||||
if (primitive.value instanceof Number) {
|
||||
Number number = (Number) primitive.value;
|
||||
return number instanceof BigInteger || number instanceof Long || number instanceof Integer
|
||||
|| number instanceof Short || number instanceof Byte;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified number is a floating point type (BigDecimal, double, float)
|
||||
*/
|
||||
private static boolean isFloatingPoint(JsonPrimitive primitive) {
|
||||
if (primitive.value instanceof Number) {
|
||||
Number number = (Number) primitive.value;
|
||||
return number instanceof BigDecimal || number instanceof Double || number instanceof Float;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
49
src/org/mcteam/factions/gson/JsonSerializationContext.java
Normal file
49
src/org/mcteam/factions/gson/JsonSerializationContext.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Context for serialization that is passed to a custom serializer during invocation of its
|
||||
* {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public interface JsonSerializationContext {
|
||||
|
||||
/**
|
||||
* Invokes default serialization on the specified object.
|
||||
*
|
||||
* @param src the object that needs to be serialized.
|
||||
* @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
|
||||
*/
|
||||
public JsonElement serialize(Object src);
|
||||
|
||||
/**
|
||||
* Invokes default serialization on the specified object passing the specific type information.
|
||||
* It should never be invoked on the element received as a parameter of the
|
||||
* {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method. Doing
|
||||
* so will result in an infinite loop since Gson will in-turn call the custom serializer again.
|
||||
*
|
||||
* @param src the object that needs to be serialized.
|
||||
* @param typeOfSrc the actual genericized type of src object.
|
||||
* @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
|
||||
*/
|
||||
public JsonElement serialize(Object src, Type typeOfSrc);
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* An implementation of serialization context for Gson.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
final class JsonSerializationContextDefault implements JsonSerializationContext {
|
||||
|
||||
private final ObjectNavigatorFactory factory;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final boolean serializeNulls;
|
||||
private final MemoryRefStack ancestors;
|
||||
|
||||
JsonSerializationContextDefault(ObjectNavigatorFactory factory, boolean serializeNulls,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers) {
|
||||
this.factory = factory;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.ancestors = new MemoryRefStack();
|
||||
}
|
||||
|
||||
public JsonElement serialize(Object src) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
return serialize(src, src.getClass(), true);
|
||||
}
|
||||
|
||||
public JsonElement serialize(Object src, Type typeOfSrc) {
|
||||
return serialize(src, typeOfSrc, true);
|
||||
}
|
||||
|
||||
public JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
|
||||
ObjectNavigator on = factory.create(new ObjectTypePair(src, typeOfSrc, preserveType));
|
||||
JsonSerializationVisitor visitor =
|
||||
new JsonSerializationVisitor(factory, serializeNulls, serializers, this, ancestors);
|
||||
on.accept(visitor);
|
||||
return visitor.getJsonElement();
|
||||
}
|
||||
}
|
236
src/org/mcteam/factions/gson/JsonSerializationVisitor.java
Normal file
236
src/org/mcteam/factions/gson/JsonSerializationVisitor.java
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A visitor that adds JSON elements corresponding to each field of an object
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
|
||||
private final ObjectNavigatorFactory factory;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final boolean serializeNulls;
|
||||
private final JsonSerializationContext context;
|
||||
private final MemoryRefStack ancestors;
|
||||
private JsonElement root;
|
||||
|
||||
JsonSerializationVisitor(ObjectNavigatorFactory factory, boolean serializeNulls,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers, JsonSerializationContext context,
|
||||
MemoryRefStack ancestors) {
|
||||
this.factory = factory;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.context = context;
|
||||
this.ancestors = ancestors;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void start(ObjectTypePair node) {
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
if (ancestors.contains(node)) {
|
||||
throw new CircularReferenceException(node);
|
||||
}
|
||||
ancestors.push(node);
|
||||
}
|
||||
|
||||
public void end(ObjectTypePair node) {
|
||||
if (node != null) {
|
||||
ancestors.pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void startVisitingObject(Object node) {
|
||||
assignToRoot(new JsonObject());
|
||||
}
|
||||
|
||||
public void visitArray(Object array, Type arrayType) {
|
||||
assignToRoot(new JsonArray());
|
||||
int length = Array.getLength(array);
|
||||
TypeInfoArray fieldTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
|
||||
Type componentType = fieldTypeInfo.getSecondLevelType();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Object child = Array.get(array, i);
|
||||
Type childType = componentType;
|
||||
// we should not get more specific component type yet since it is possible
|
||||
// that a custom
|
||||
// serializer is registered for the componentType
|
||||
addAsArrayElement(new ObjectTypePair(child, childType, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (isFieldNull(f, obj)) {
|
||||
if (serializeNulls) {
|
||||
addChildAsElement(f, JsonNull.createJsonNull());
|
||||
}
|
||||
} else {
|
||||
Object array = getFieldValue(f, obj);
|
||||
addAsChildOfObject(f, new ObjectTypePair(array, typeOfF, false));
|
||||
}
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(f);
|
||||
}
|
||||
}
|
||||
|
||||
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (isFieldNull(f, obj)) {
|
||||
if (serializeNulls) {
|
||||
addChildAsElement(f, JsonNull.createJsonNull());
|
||||
}
|
||||
} else {
|
||||
Object fieldValue = getFieldValue(f, obj);
|
||||
// we should not get more specific component type yet since it is
|
||||
// possible that a custom
|
||||
// serializer is registered for the componentType
|
||||
addAsChildOfObject(f, new ObjectTypePair(fieldValue, typeOfF, false));
|
||||
}
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(f);
|
||||
}
|
||||
}
|
||||
|
||||
public void visitPrimitive(Object obj) {
|
||||
JsonElement json = obj == null ? JsonNull.createJsonNull() : new JsonPrimitive(obj);
|
||||
assignToRoot(json);
|
||||
}
|
||||
|
||||
private void addAsChildOfObject(FieldAttributes f, ObjectTypePair fieldValuePair) {
|
||||
JsonElement childElement = getJsonElementForChild(fieldValuePair);
|
||||
addChildAsElement(f, childElement);
|
||||
}
|
||||
|
||||
private void addChildAsElement(FieldAttributes f, JsonElement childElement) {
|
||||
FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
|
||||
root.getAsJsonObject().add(namingPolicy.translateName(f), childElement);
|
||||
}
|
||||
|
||||
private void addAsArrayElement(ObjectTypePair elementTypePair) {
|
||||
if (elementTypePair.getObject() == null) {
|
||||
root.getAsJsonArray().add(JsonNull.createJsonNull());
|
||||
} else {
|
||||
JsonElement childElement = getJsonElementForChild(elementTypePair);
|
||||
root.getAsJsonArray().add(childElement);
|
||||
}
|
||||
}
|
||||
|
||||
private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) {
|
||||
ObjectNavigator on = factory.create(fieldValueTypePair);
|
||||
JsonSerializationVisitor childVisitor =
|
||||
new JsonSerializationVisitor(factory, serializeNulls, serializers, context, ancestors);
|
||||
on.accept(childVisitor);
|
||||
return childVisitor.getJsonElement();
|
||||
}
|
||||
|
||||
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
|
||||
try {
|
||||
Object obj = objTypePair.getObject();
|
||||
if (obj == null) {
|
||||
if (serializeNulls) {
|
||||
assignToRoot(JsonNull.createJsonNull());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
JsonElement element = findAndInvokeCustomSerializer(objTypePair);
|
||||
if (element != null) {
|
||||
assignToRoot(element);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* objTypePair.getObject() must not be null
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private JsonElement findAndInvokeCustomSerializer(ObjectTypePair objTypePair) {
|
||||
Pair<JsonSerializer<?>,ObjectTypePair> pair = objTypePair.getMatchingHandler(serializers);
|
||||
if (pair == null) {
|
||||
return null;
|
||||
}
|
||||
JsonSerializer serializer = pair.first;
|
||||
objTypePair = pair.second;
|
||||
start(objTypePair);
|
||||
try {
|
||||
JsonElement element =
|
||||
serializer.serialize(objTypePair.getObject(), objTypePair.getType(), context);
|
||||
return element == null ? JsonNull.createJsonNull() : element;
|
||||
} finally {
|
||||
end(objTypePair);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
|
||||
try {
|
||||
Preconditions.checkState(root.isJsonObject());
|
||||
Object obj = f.get(parent);
|
||||
if (obj == null) {
|
||||
if (serializeNulls) {
|
||||
addChildAsElement(f, JsonNull.createJsonNull());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ObjectTypePair objTypePair = new ObjectTypePair(obj, declaredTypeOfField, false);
|
||||
JsonElement child = findAndInvokeCustomSerializer(objTypePair);
|
||||
if (child != null) {
|
||||
addChildAsElement(f, child);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException();
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(f);
|
||||
}
|
||||
}
|
||||
|
||||
private void assignToRoot(JsonElement newRoot) {
|
||||
Preconditions.checkNotNull(newRoot);
|
||||
root = newRoot;
|
||||
}
|
||||
|
||||
private boolean isFieldNull(FieldAttributes f, Object obj) {
|
||||
return getFieldValue(f, obj) == null;
|
||||
}
|
||||
|
||||
private Object getFieldValue(FieldAttributes f, Object obj) {
|
||||
try {
|
||||
return f.get(obj);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public JsonElement getJsonElement() {
|
||||
return root;
|
||||
}
|
||||
}
|
86
src/org/mcteam/factions/gson/JsonSerializer.java
Normal file
86
src/org/mcteam/factions/gson/JsonSerializer.java
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Interface representing a custom serializer for Json. You should write a custom serializer, if
|
||||
* you are not happy with the default serialization done by Gson. You will also need to register
|
||||
* this serializer through {@link org.mcteam.factions.gson.GsonBuilder#registerTypeAdapter(Type, Object)}.
|
||||
*
|
||||
* <p>Let us look at example where defining a serializer will be useful. The {@code Id} class
|
||||
* defined below has two fields: {@code clazz} and {@code value}.</p>
|
||||
*
|
||||
* <p><pre>
|
||||
* public class Id<T> {
|
||||
* private final Class<T> clazz;
|
||||
* private final long value;
|
||||
*
|
||||
* public Id(Class<T> clazz, long value) {
|
||||
* this.clazz = clazz;
|
||||
* this.value = value;
|
||||
* }
|
||||
*
|
||||
* public long getValue() {
|
||||
* return value;
|
||||
* }
|
||||
* }
|
||||
* </pre></p>
|
||||
*
|
||||
* <p>The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be
|
||||
* <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you just want the output to be
|
||||
* the value instead, which is {@code 20} in this case. You can achieve that by writing a custom
|
||||
* serializer:</p>
|
||||
*
|
||||
* <p><pre>
|
||||
* class IdSerializer implements JsonSerializer<Id>() {
|
||||
* public JsonElement toJson(Id id, Type typeOfId, JsonSerializationContext context) {
|
||||
* return new JsonPrimitive(id.getValue());
|
||||
* }
|
||||
* }
|
||||
* </pre></p>
|
||||
*
|
||||
* <p>You will also need to register {@code IdSerializer} with Gson as follows:</p>
|
||||
* <pre>
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).create();
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @param <T> type for which the serializer is being registered. It is possible that a serializer
|
||||
* may be asked to serialize a specific generic type of the T.
|
||||
*/
|
||||
public interface JsonSerializer<T> {
|
||||
|
||||
/**
|
||||
* Gson invokes this call-back method during serialization when it encounters a field of the
|
||||
* specified type.
|
||||
*
|
||||
* <p>In the implementation of this call-back method, you should consider invoking
|
||||
* {@link JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any
|
||||
* non-trivial field of the {@code src} object. However, you should never invoke it on the
|
||||
* {@code src} object itself since that will cause an infinite loop (Gson will call your
|
||||
* call-back method again).</p>
|
||||
*
|
||||
* @param src the object that needs to be converted to Json.
|
||||
* @param typeOfSrc the actual type (fully genericized version) of the source object.
|
||||
* @return a JsonElement corresponding to the specified object.
|
||||
*/
|
||||
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);
|
||||
}
|
123
src/org/mcteam/factions/gson/JsonStreamParser.java
Normal file
123
src/org/mcteam/factions/gson/JsonStreamParser.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonToken;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
|
||||
|
||||
/**
|
||||
* A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
|
||||
* asynchronously.
|
||||
*
|
||||
* <p>This class is conditionally thread-safe (see Item 70, Effective Java second edition). To
|
||||
* properly use this class across multiple threads, you will need to add some external
|
||||
* synchronization. For example:
|
||||
*
|
||||
* <pre>
|
||||
* JsonStreamParser parser = new JsonStreamParser("['first'] {'second':10} 'third'");
|
||||
* JsonElement element;
|
||||
* synchronized (parser) { // synchronize on an object shared by threads
|
||||
* if (parser.hasNext()) {
|
||||
* element = parser.next();
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @since 1.4
|
||||
*/
|
||||
public final class JsonStreamParser implements Iterator<JsonElement> {
|
||||
|
||||
private final JsonReader parser;
|
||||
private final Object lock;
|
||||
|
||||
/**
|
||||
* @param json The string containing JSON elements concatenated to each other.
|
||||
* @since 1.4
|
||||
*/
|
||||
public JsonStreamParser(String json) {
|
||||
this(new StringReader(json));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reader The data stream containing JSON elements concatenated to each other.
|
||||
* @since 1.4
|
||||
*/
|
||||
public JsonStreamParser(Reader reader) {
|
||||
parser = new JsonReader(reader);
|
||||
parser.setLenient(true);
|
||||
lock = new Object();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next available {@link JsonElement} on the reader. Null if none available.
|
||||
*
|
||||
* @return the next available {@link JsonElement} on the reader. Null if none available.
|
||||
* @throws JsonParseException if the incoming stream is malformed JSON.
|
||||
* @since 1.4
|
||||
*/
|
||||
public JsonElement next() throws JsonParseException {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
try {
|
||||
return Streams.parse(parser);
|
||||
} catch (StackOverflowError e) {
|
||||
throw new JsonParseException("Failed parsing JSON source to Json", e);
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw new JsonParseException("Failed parsing JSON source to Json", e);
|
||||
} catch (JsonParseException e) {
|
||||
throw e.getCause() instanceof EOFException ? new NoSuchElementException() : e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a {@link JsonElement} is available on the input for consumption
|
||||
* @return true if a {@link JsonElement} is available on the input, false otherwise
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
synchronized (lock) {
|
||||
try {
|
||||
return parser.peek() != JsonToken.END_DOCUMENT;
|
||||
} catch (MalformedJsonException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This optional {@link Iterator} method is not relevant for stream parsing and hence is not
|
||||
* implemented.
|
||||
* @since 1.4
|
||||
*/
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
47
src/org/mcteam/factions/gson/JsonSyntaxException.java
Normal file
47
src/org/mcteam/factions/gson/JsonSyntaxException.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* This exception is raised when Gson attempts to read (or write) a malformed
|
||||
* JSON element.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class JsonSyntaxException extends JsonParseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JsonSyntaxException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public JsonSyntaxException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates exception with the specified cause. Consider using
|
||||
* {@link #JsonSyntaxException(String, Throwable)} instead if you can
|
||||
* describe what actually happened.
|
||||
*
|
||||
* @param cause root exception that caused this exception to be thrown.
|
||||
*/
|
||||
public JsonSyntaxException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
111
src/org/mcteam/factions/gson/JsonTreeNavigator.java
Normal file
111
src/org/mcteam/factions/gson/JsonTreeNavigator.java
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A navigator to navigate a tree of JsonElement nodes in Depth-first order
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
final class JsonTreeNavigator {
|
||||
private final JsonElementVisitor visitor;
|
||||
private final boolean visitNulls;
|
||||
|
||||
JsonTreeNavigator(JsonElementVisitor visitor, boolean visitNulls) {
|
||||
this.visitor = visitor;
|
||||
this.visitNulls = visitNulls;
|
||||
}
|
||||
|
||||
public void navigate(JsonElement element) throws IOException {
|
||||
if (element.isJsonNull()) {
|
||||
visitor.visitNull();
|
||||
} else if (element.isJsonArray()) {
|
||||
JsonArray array = element.getAsJsonArray();
|
||||
visitor.startArray(array);
|
||||
boolean isFirst = true;
|
||||
for (JsonElement child : array) {
|
||||
visitChild(array, child, isFirst);
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
visitor.endArray(array);
|
||||
} else if (element.isJsonObject()) {
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
visitor.startObject(object);
|
||||
boolean isFirst = true;
|
||||
for (Map.Entry<String, JsonElement> member : object.entrySet()) {
|
||||
boolean visited = visitChild(object, member.getKey(), member.getValue(), isFirst);
|
||||
if (visited && isFirst) {
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
visitor.endObject(object);
|
||||
} else { // must be JsonPrimitive
|
||||
visitor.visitPrimitive(element.getAsJsonPrimitive());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the child was visited, false if it was skipped.
|
||||
*/
|
||||
private boolean visitChild(JsonObject parent, String childName, JsonElement child,
|
||||
boolean isFirst) throws IOException {
|
||||
if (child.isJsonNull()) {
|
||||
if (visitNulls) {
|
||||
visitor.visitNullObjectMember(parent, childName, isFirst);
|
||||
navigate(child.getAsJsonNull());
|
||||
} else { // Null value is being skipped.
|
||||
return false;
|
||||
}
|
||||
} else if (child.isJsonArray()) {
|
||||
JsonArray childAsArray = child.getAsJsonArray();
|
||||
visitor.visitObjectMember(parent, childName, childAsArray, isFirst);
|
||||
navigate(childAsArray);
|
||||
} else if (child.isJsonObject()) {
|
||||
JsonObject childAsObject = child.getAsJsonObject();
|
||||
visitor.visitObjectMember(parent, childName, childAsObject, isFirst);
|
||||
navigate(childAsObject);
|
||||
} else { // is a JsonPrimitive
|
||||
visitor.visitObjectMember(parent, childName, child.getAsJsonPrimitive(), isFirst);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the child was visited, false if it was skipped.
|
||||
*/
|
||||
private void visitChild(JsonArray parent, JsonElement child, boolean isFirst) throws IOException {
|
||||
if (child.isJsonNull()) {
|
||||
visitor.visitNullArrayMember(parent, isFirst);
|
||||
navigate(child);
|
||||
} else if (child.isJsonArray()) {
|
||||
JsonArray childAsArray = child.getAsJsonArray();
|
||||
visitor.visitArrayMember(parent, childAsArray, isFirst);
|
||||
navigate(childAsArray);
|
||||
} else if (child.isJsonObject()) {
|
||||
JsonObject childAsObject = child.getAsJsonObject();
|
||||
visitor.visitArrayMember(parent, childAsObject, isFirst);
|
||||
navigate(childAsObject);
|
||||
} else { // is a JsonPrimitive
|
||||
visitor.visitArrayMember(parent, child.getAsJsonPrimitive(), isFirst);
|
||||
}
|
||||
}
|
||||
}
|
74
src/org/mcteam/factions/gson/LongSerializationPolicy.java
Normal file
74
src/org/mcteam/factions/gson/LongSerializationPolicy.java
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* Defines the expected format for a {@code long} or {@code Long} type when its serialized.
|
||||
*
|
||||
* @since 1.3
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public enum LongSerializationPolicy {
|
||||
/**
|
||||
* This is the "default" serialization policy that will output a {@code long} object as a JSON
|
||||
* number. For example, assume an object has a long field named "f" then the serialized output
|
||||
* would be:
|
||||
* {@code {"f":123}}.
|
||||
*/
|
||||
DEFAULT(new DefaultStrategy()),
|
||||
|
||||
/**
|
||||
* Serializes a long value as a quoted string. For example, assume an object has a long field
|
||||
* named "f" then the serialized output would be:
|
||||
* {@code {"f":"123"}}.
|
||||
*/
|
||||
STRING(new StringStrategy());
|
||||
|
||||
private final Strategy strategy;
|
||||
|
||||
private LongSerializationPolicy(Strategy strategy) {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize this {@code value} using this serialization policy.
|
||||
*
|
||||
* @param value the long value to be serialized into a {@link JsonElement}
|
||||
* @return the serialized version of {@code value}
|
||||
*/
|
||||
public JsonElement serialize(Long value) {
|
||||
return strategy.serialize(value);
|
||||
}
|
||||
|
||||
private interface Strategy {
|
||||
JsonElement serialize(Long value);
|
||||
}
|
||||
|
||||
private static class DefaultStrategy implements Strategy {
|
||||
public JsonElement serialize(Long value) {
|
||||
return new JsonPrimitive(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringStrategy implements Strategy {
|
||||
public JsonElement serialize(Long value) {
|
||||
return new JsonPrimitive(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
|
||||
* lower case letters and are separated by a particular {@code separatorString}.
|
||||
*
|
||||
*<p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class StringWrapper {
|
||||
* public String AStringField = "abcd";
|
||||
* }
|
||||
*
|
||||
* LowerCamelCaseSeparatorNamingPolicy policy = new LowerCamelCaseSeparatorNamingPolicy("_");
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("AStringField"));
|
||||
*
|
||||
* assert("a_string_field".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class LowerCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
|
||||
|
||||
public LowerCamelCaseSeparatorNamingPolicy(String separatorString) {
|
||||
super(new CamelCaseSeparatorNamingPolicy(separatorString), new LowerCaseNamingPolicy());
|
||||
}
|
||||
}
|
50
src/org/mcteam/factions/gson/LowerCaseNamingPolicy.java
Normal file
50
src/org/mcteam/factions/gson/LowerCaseNamingPolicy.java
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
|
||||
* lower case letters.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* LowerCaseNamingPolicy policy = new LowerCaseNamingPolicy();
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("integerfield".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class LowerCaseNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType,
|
||||
Collection<Annotation> annotations) {
|
||||
return target.toLowerCase();
|
||||
}
|
||||
}
|
66
src/org/mcteam/factions/gson/LruCache.java
Normal file
66
src/org/mcteam/factions/gson/LruCache.java
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implementation of the {@link Cache} interface that evict objects from the cache using an
|
||||
* LRU (least recently used) algorithm. Object start getting evicted from the cache once the
|
||||
* {@code maxCapacity} is reached.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class LruCache<K, V> extends LinkedHashMap<K, V> implements Cache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final int maxCapacity;
|
||||
|
||||
LruCache(int maxCapacity) {
|
||||
super(maxCapacity, 0.7F, true);
|
||||
this.maxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
public void addElement(K key, V value) {
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
}
|
||||
|
||||
public V getElement(K key) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
public V removeElement(K key) {
|
||||
return remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return super.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
|
||||
return size() > maxCapacity;
|
||||
}
|
||||
}
|
168
src/org/mcteam/factions/gson/MapAsArrayTypeAdapter.java
Normal file
168
src/org/mcteam/factions/gson/MapAsArrayTypeAdapter.java
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapts maps containing complex keys as arrays of map entries.
|
||||
*
|
||||
* <h3>Maps as JSON objects</h3>
|
||||
* The standard GSON map type adapter converts Java {@link Map Maps} to JSON
|
||||
* Objects. This requires that map keys can be serialized as strings; this is
|
||||
* insufficient for some key types. For example, consider a map whose keys are
|
||||
* points on a grid. The default JSON form encodes reasonably: <pre> {@code
|
||||
* Map<Point, String> original = new LinkedHashMap<Point, String>();
|
||||
* original.put(new Point(5, 6), "a");
|
||||
* original.put(new Point(8, 8), "b");
|
||||
* System.out.println(gson.toJson(original, type));
|
||||
* }</pre>
|
||||
* The above code prints this JSON object:<pre> {@code
|
||||
* {
|
||||
* "(5,6)": "a",
|
||||
* "(8,8)": "b"
|
||||
* }
|
||||
* }</pre>
|
||||
* But GSON is unable to deserialize this value because the JSON string name is
|
||||
* just the {@link Object#toString() toString()} of the map key. Attempting to
|
||||
* convert the above JSON to an object fails with a parse exception:
|
||||
* <pre>com.bukkit.mcteam.gson.JsonParseException: Expecting object found: "(5,6)"
|
||||
* at com.bukkit.mcteam.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
|
||||
* at com.bukkit.mcteam.gson.ObjectNavigator.navigateClassFields
|
||||
* ...</pre>
|
||||
*
|
||||
* <h3>Maps as JSON arrays</h3>
|
||||
* An alternative approach taken by this type adapter is to encode maps as
|
||||
* arrays of map entries. Each map entry is a two element array containing a key
|
||||
* and a value. This approach is more flexible because any type can be used as
|
||||
* the map's key; not just strings. But it's also less portable because the
|
||||
* receiver of such JSON must be aware of the map entry convention.
|
||||
*
|
||||
* <p>Register this adapter when you are creating your GSON instance.
|
||||
* <pre> {@code
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .registerTypeAdapter(Map.class, new MapAsArrayTypeAdapter())
|
||||
* .create();
|
||||
* }</pre>
|
||||
* This will change the structure of the JSON emitted by the code above. Now we
|
||||
* get an array. In this case the arrays elements are map entries:
|
||||
* <pre> {@code
|
||||
* [
|
||||
* [
|
||||
* {
|
||||
* "x": 5,
|
||||
* "y": 6
|
||||
* },
|
||||
* "a",
|
||||
* ],
|
||||
* [
|
||||
* {
|
||||
* "x": 8,
|
||||
* "y": 8
|
||||
* },
|
||||
* "b"
|
||||
* ]
|
||||
* ]
|
||||
* }</pre>
|
||||
* This format will serialize and deserialize just fine as long as this adapter
|
||||
* is registered.
|
||||
*
|
||||
* <p>This adapter returns regular JSON objects for maps whose keys are not
|
||||
* complex. A key is complex if its JSON-serialized form is an array or an
|
||||
* object.
|
||||
*/
|
||||
public final class MapAsArrayTypeAdapter
|
||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
public Map<?, ?> deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
Map<Object, Object> result = new LinkedHashMap<Object, Object>();
|
||||
Type[] keyAndValueType = typeToTypeArguments(typeOfT);
|
||||
if (json.isJsonArray()) {
|
||||
JsonArray array = json.getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
JsonArray entryArray = array.get(i).getAsJsonArray();
|
||||
Object k = context.deserialize(entryArray.get(0), keyAndValueType[0]);
|
||||
Object v = context.deserialize(entryArray.get(1), keyAndValueType[1]);
|
||||
result.put(k, v);
|
||||
}
|
||||
checkSize(array, array.size(), result, result.size());
|
||||
} else {
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
|
||||
Object k = context.deserialize(new JsonPrimitive(entry.getKey()), keyAndValueType[0]);
|
||||
Object v = context.deserialize(entry.getValue(), keyAndValueType[1]);
|
||||
result.put(k, v);
|
||||
}
|
||||
checkSize(object, object.entrySet().size(), result, result.size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public JsonElement serialize(Map<?, ?> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
Type[] keyAndValueType = typeToTypeArguments(typeOfSrc);
|
||||
boolean serializeAsArray = false;
|
||||
List<JsonElement> keysAndValues = new ArrayList<JsonElement>();
|
||||
for (Map.Entry<?, ?> entry : src.entrySet()) {
|
||||
JsonElement key = context.serialize(entry.getKey(), keyAndValueType[0]);
|
||||
serializeAsArray |= key.isJsonObject() || key.isJsonArray();
|
||||
keysAndValues.add(key);
|
||||
keysAndValues.add(context.serialize(entry.getValue(), keyAndValueType[1]));
|
||||
}
|
||||
|
||||
if (serializeAsArray) {
|
||||
JsonArray result = new JsonArray();
|
||||
for (int i = 0; i < keysAndValues.size(); i+=2) {
|
||||
JsonArray entryArray = new JsonArray();
|
||||
entryArray.add(keysAndValues.get(i));
|
||||
entryArray.add(keysAndValues.get(i + 1));
|
||||
result.add(entryArray);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
JsonObject result = new JsonObject();
|
||||
for (int i = 0; i < keysAndValues.size(); i+=2) {
|
||||
result.add(keysAndValues.get(i).getAsString(), keysAndValues.get(i + 1));
|
||||
}
|
||||
checkSize(src, src.size(), result, result.entrySet().size());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] typeToTypeArguments(Type typeOfT) {
|
||||
if (typeOfT instanceof ParameterizedType) {
|
||||
Type[] typeArguments = ((ParameterizedType) typeOfT).getActualTypeArguments();
|
||||
if (typeArguments.length != 2) {
|
||||
throw new IllegalArgumentException("MapAsArrayTypeAdapter cannot handle " + typeOfT);
|
||||
}
|
||||
return typeArguments;
|
||||
}
|
||||
return new Type[] { Object.class, Object.class };
|
||||
}
|
||||
|
||||
private void checkSize(Object input, int inputSize, Object output, int outputSize) {
|
||||
if (inputSize != outputSize) {
|
||||
throw new JsonSyntaxException("Input size " + inputSize + " != output size " + outputSize
|
||||
+ " for input " + input + " and output " + output);
|
||||
}
|
||||
}
|
||||
}
|
112
src/org/mcteam/factions/gson/MappedObjectConstructor.java
Normal file
112
src/org/mcteam/factions/gson/MappedObjectConstructor.java
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class contains a mapping of all the application specific
|
||||
* {@link InstanceCreator} instances. Registering an {@link InstanceCreator}
|
||||
* with this class will override the default object creation that is defined
|
||||
* by the ObjectConstructor that this class is wrapping. Using this class
|
||||
* with the JSON framework provides the application with "pluggable" modules
|
||||
* to customize framework to suit the application's needs.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class MappedObjectConstructor implements ObjectConstructor {
|
||||
private static final Logger log = Logger.getLogger(MappedObjectConstructor.class.getName());
|
||||
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreatorMap;
|
||||
|
||||
public MappedObjectConstructor(
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) {
|
||||
instanceCreatorMap = instanceCreators;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T construct(Type typeOfT) {
|
||||
InstanceCreator<T> creator = (InstanceCreator<T>) instanceCreatorMap.getHandlerFor(typeOfT);
|
||||
if (creator != null) {
|
||||
return creator.createInstance(typeOfT);
|
||||
}
|
||||
return (T) constructWithNoArgConstructor(typeOfT);
|
||||
}
|
||||
|
||||
public Object constructArray(Type type, int length) {
|
||||
return Array.newInstance(TypeUtils.toRawClass(type), length);
|
||||
}
|
||||
|
||||
private <T> T constructWithNoArgConstructor(Type typeOfT) {
|
||||
try {
|
||||
Constructor<T> constructor = getNoArgsConstructor(typeOfT);
|
||||
if (constructor == null) {
|
||||
throw new RuntimeException(("No-args constructor for " + typeOfT + " does not exist. "
|
||||
+ "Register an InstanceCreator with Gson for this type to fix this problem."));
|
||||
}
|
||||
return constructor.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
|
||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
|
||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
|
||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "cast"})
|
||||
private <T> Constructor<T> getNoArgsConstructor(Type typeOfT) {
|
||||
TypeInfo typeInfo = new TypeInfo(typeOfT);
|
||||
Class<T> clazz = (Class<T>) typeInfo.getRawClass();
|
||||
Constructor<T>[] declaredConstructors = (Constructor<T>[]) clazz.getDeclaredConstructors();
|
||||
AccessibleObject.setAccessible(declaredConstructors, true);
|
||||
for (Constructor<T> constructor : declaredConstructors) {
|
||||
if (constructor.getParameterTypes().length == 0) {
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this methods to register an {@link InstanceCreator} for a new type.
|
||||
*
|
||||
* @param <T> the type of class to be mapped with its "creator"
|
||||
* @param typeOfT the instance type that will be created
|
||||
* @param creator the {@link InstanceCreator} instance to register
|
||||
*/
|
||||
<T> void register(Type typeOfT, InstanceCreator<? extends T> creator) {
|
||||
if (instanceCreatorMap.hasSpecificHandlerFor(typeOfT)) {
|
||||
log.log(Level.WARNING, "Overriding the existing InstanceCreator for {0}", typeOfT);
|
||||
}
|
||||
instanceCreatorMap.register(typeOfT, creator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return instanceCreatorMap.toString();
|
||||
}
|
||||
}
|
87
src/org/mcteam/factions/gson/MemoryRefStack.java
Normal file
87
src/org/mcteam/factions/gson/MemoryRefStack.java
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* A stack data structure that only does a memory reference comparison
|
||||
* when looking for a particular item in the stack. This stack does
|
||||
* not allow {@code null} values to be added.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class MemoryRefStack {
|
||||
private final Stack<ObjectTypePair> stack = new Stack<ObjectTypePair>();
|
||||
|
||||
/**
|
||||
* Adds a new element to the top of the stack.
|
||||
*
|
||||
* @param obj the object to add to the stack
|
||||
* @return the object that was added
|
||||
*/
|
||||
public ObjectTypePair push(ObjectTypePair obj) {
|
||||
Preconditions.checkNotNull(obj);
|
||||
|
||||
return stack.push(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the top element from the stack.
|
||||
*
|
||||
* @return the element being removed from the stack
|
||||
* @throws java.util.EmptyStackException thrown if the stack is empty
|
||||
*/
|
||||
public ObjectTypePair pop() {
|
||||
return stack.pop();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return stack.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the item from the top of the stack, but does not remove it.
|
||||
*
|
||||
* @return the item from the top of the stack
|
||||
* @throws java.util.EmptyStackException thrown if the stack is empty
|
||||
*/
|
||||
public ObjectTypePair peek() {
|
||||
return stack.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a memory reference check to see it the {@code obj} exists in
|
||||
* the stack.
|
||||
*
|
||||
* @param obj the object to search for in the stack
|
||||
* @return true if this object is already in the stack otherwise false
|
||||
*/
|
||||
public boolean contains(ObjectTypePair obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ObjectTypePair stackObject : stack) {
|
||||
if (stackObject.getObject() == obj.getObject()
|
||||
&& stackObject.type.equals(obj.type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Exclude fields based on particular field modifiers. For a list of possible
|
||||
* modifiers, see {@link java.lang.reflect.Modifier}.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ModifierBasedExclusionStrategy implements ExclusionStrategy {
|
||||
private final Collection<Integer> modifiers;
|
||||
|
||||
public ModifierBasedExclusionStrategy(int... modifiers) {
|
||||
this.modifiers = new HashSet<Integer>();
|
||||
if (modifiers != null) {
|
||||
for (int modifier : modifiers) {
|
||||
this.modifiers.add(modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
for (int modifier : modifiers) {
|
||||
if (f.hasModifier(modifier)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}
|
107
src/org/mcteam/factions/gson/ModifyFirstLetterNamingPolicy.java
Normal file
107
src/org/mcteam/factions/gson/ModifyFirstLetterNamingPolicy.java
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names begins with
|
||||
* an upper case letter.
|
||||
*
|
||||
*<p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class StringWrapper {
|
||||
* public String stringField = "abcd";
|
||||
* public String _stringField = "efg";
|
||||
* }
|
||||
*
|
||||
* ModifyFirstLetterNamingPolicy policy =
|
||||
* new ModifyFirstLetterNamingPolicy(LetterModifier.UPPER);
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("stringField"));
|
||||
*
|
||||
* assert("StringField".equals(translatedFieldName));
|
||||
*
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("_stringField"));
|
||||
*
|
||||
* assert("_StringField".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
public enum LetterModifier {
|
||||
UPPER,
|
||||
LOWER;
|
||||
}
|
||||
|
||||
private final LetterModifier letterModifier;
|
||||
|
||||
/**
|
||||
* Creates a new ModifyFirstLetterNamingPolicy that will either modify the first letter of the
|
||||
* target name to either UPPER case or LOWER case depending on the {@code modifier} parameter.
|
||||
*
|
||||
* @param modifier the type of modification that should be performed
|
||||
* @throws IllegalArgumentException if {@code modifier} is null
|
||||
*/
|
||||
public ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
|
||||
Preconditions.checkNotNull(modifier);
|
||||
this.letterModifier = modifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType,
|
||||
Collection<Annotation> annotations) {
|
||||
StringBuilder fieldNameBuilder = new StringBuilder();
|
||||
int index = 0;
|
||||
char firstCharacter = target.charAt(index);
|
||||
|
||||
while (index < target.length() - 1) {
|
||||
if (Character.isLetter(firstCharacter)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fieldNameBuilder.append(firstCharacter);
|
||||
firstCharacter = target.charAt(++index);
|
||||
}
|
||||
|
||||
if (index == target.length()) {
|
||||
return fieldNameBuilder.toString();
|
||||
}
|
||||
|
||||
boolean capitalizeFirstLetter = (letterModifier == LetterModifier.UPPER);
|
||||
if (capitalizeFirstLetter && !Character.isUpperCase(firstCharacter)) {
|
||||
String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), target, ++index);
|
||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
||||
} else if (!capitalizeFirstLetter && Character.isUpperCase(firstCharacter)) {
|
||||
String modifiedTarget = modifyString(Character.toLowerCase(firstCharacter), target, ++index);
|
||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
||||
} else {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
|
||||
return indexOfSubstring < srcString.length() ?
|
||||
firstCharacter + srcString.substring(indexOfSubstring)
|
||||
: String.valueOf(firstCharacter);
|
||||
}
|
||||
}
|
37
src/org/mcteam/factions/gson/NullExclusionStrategy.java
Normal file
37
src/org/mcteam/factions/gson/NullExclusionStrategy.java
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
/**
|
||||
* This acts as a "Null Object" pattern for the {@link ExclusionStrategy}.
|
||||
* Passing an instance of this class into the {@link ObjectNavigator} will
|
||||
* make the {@link ObjectNavigator} parse/visit every field of the object
|
||||
* being navigated.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class NullExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}
|
47
src/org/mcteam/factions/gson/ObjectConstructor.java
Normal file
47
src/org/mcteam/factions/gson/ObjectConstructor.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Defines a generic object construction factory. The purpose of this class
|
||||
* is to construct a default instance of a class that can be used for object
|
||||
* navigation while deserialization from its JSON representation.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
interface ObjectConstructor {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the given type.
|
||||
*
|
||||
* @param typeOfT the class type that should be instantiated
|
||||
* @return a default instance of the provided class.
|
||||
*/
|
||||
public <T> T construct(Type typeOfT);
|
||||
|
||||
/**
|
||||
* Constructs an array type of the provided length.
|
||||
*
|
||||
* @param typeOfArrayElements type of objects in the array
|
||||
* @param length size of the array
|
||||
* @return new array of size length
|
||||
*/
|
||||
public Object constructArray(Type typeOfArrayElements, int length);
|
||||
}
|
169
src/org/mcteam/factions/gson/ObjectNavigator.java
Normal file
169
src/org/mcteam/factions/gson/ObjectNavigator.java
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Provides ability to apply a visitor to an object and all of its fields
|
||||
* recursively.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ObjectNavigator {
|
||||
|
||||
public interface Visitor {
|
||||
public void start(ObjectTypePair node);
|
||||
|
||||
public void end(ObjectTypePair node);
|
||||
|
||||
/**
|
||||
* This is called before the object navigator starts visiting the current
|
||||
* object
|
||||
*/
|
||||
void startVisitingObject(Object node);
|
||||
|
||||
/**
|
||||
* This is called to visit the current object if it is an array
|
||||
*/
|
||||
void visitArray(Object array, Type componentType);
|
||||
|
||||
/**
|
||||
* This is called to visit an object field of the current object
|
||||
*/
|
||||
void visitObjectField(FieldAttributes f, Type typeOfF, Object obj);
|
||||
|
||||
/**
|
||||
* This is called to visit an array field of the current object
|
||||
*/
|
||||
void visitArrayField(FieldAttributes f, Type typeOfF, Object obj);
|
||||
|
||||
/**
|
||||
* This is called to visit an object using a custom handler
|
||||
*
|
||||
* @return true if a custom handler exists, false otherwise
|
||||
*/
|
||||
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair);
|
||||
|
||||
/**
|
||||
* This is called to visit a field of the current object using a custom
|
||||
* handler
|
||||
*/
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField,
|
||||
Object parent);
|
||||
|
||||
/**
|
||||
* Retrieve the current target
|
||||
*/
|
||||
Object getTarget();
|
||||
|
||||
void visitPrimitive(Object primitive);
|
||||
}
|
||||
|
||||
private final ExclusionStrategy exclusionStrategy;
|
||||
private final ObjectTypePair objTypePair;
|
||||
|
||||
/**
|
||||
* @param objTypePair
|
||||
* The object,type (fully genericized) being navigated
|
||||
* @param exclusionStrategy
|
||||
* the concrete strategy object to be used to filter out fields of an
|
||||
* object.
|
||||
*/
|
||||
ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) {
|
||||
Preconditions.checkNotNull(exclusionStrategy);
|
||||
|
||||
this.objTypePair = objTypePair;
|
||||
this.exclusionStrategy = exclusionStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate all the fields of the specified object. If a field is null, it
|
||||
* does not get visited.
|
||||
*/
|
||||
public void accept(Visitor visitor) {
|
||||
TypeInfo objTypeInfo = new TypeInfo(objTypePair.type);
|
||||
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
|
||||
return;
|
||||
}
|
||||
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
|
||||
if (!visitedWithCustomHandler) {
|
||||
Object obj = objTypePair.getObject();
|
||||
Object objectToVisit = (obj == null) ? visitor.getTarget() : obj;
|
||||
if (objectToVisit == null) {
|
||||
return;
|
||||
}
|
||||
objTypePair.setObject(objectToVisit);
|
||||
visitor.start(objTypePair);
|
||||
try {
|
||||
if (objTypeInfo.isArray()) {
|
||||
visitor.visitArray(objectToVisit, objTypePair.type);
|
||||
} else if (objTypeInfo.getActualType() == Object.class
|
||||
&& isPrimitiveOrString(objectToVisit)) {
|
||||
// TODO(Joel): this is only used for deserialization of "primitives"
|
||||
// we should rethink this!!!
|
||||
visitor.visitPrimitive(objectToVisit);
|
||||
objectToVisit = visitor.getTarget();
|
||||
} else {
|
||||
visitor.startVisitingObject(objectToVisit);
|
||||
ObjectTypePair currObjTypePair = objTypePair.toMoreSpecificType();
|
||||
Class<?> topLevelClass = new TypeInfo(currObjTypePair.type).getRawClass();
|
||||
for (Class<?> curr = topLevelClass; curr != null && !curr.equals(Object.class); curr =
|
||||
curr.getSuperclass()) {
|
||||
if (!curr.isSynthetic()) {
|
||||
navigateClassFields(objectToVisit, curr, visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
visitor.end(objTypePair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPrimitiveOrString(Object objectToVisit) {
|
||||
Class<?> realClazz = objectToVisit.getClass();
|
||||
return realClazz == Object.class || realClazz == String.class
|
||||
|| Primitives.unwrap(realClazz).isPrimitive();
|
||||
}
|
||||
|
||||
private void navigateClassFields(Object obj, Class<?> clazz, Visitor visitor) {
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
AccessibleObject.setAccessible(fields, true);
|
||||
for (Field f : fields) {
|
||||
FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
|
||||
if (exclusionStrategy.shouldSkipField(fieldAttributes)
|
||||
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
|
||||
continue; // skip
|
||||
}
|
||||
TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.type);
|
||||
Type declaredTypeOfField = fieldTypeInfo.getActualType();
|
||||
boolean visitedWithCustomHandler =
|
||||
visitor.visitFieldUsingCustomHandler(fieldAttributes, declaredTypeOfField, obj);
|
||||
if (!visitedWithCustomHandler) {
|
||||
if (fieldTypeInfo.isArray()) {
|
||||
visitor.visitArrayField(fieldAttributes, declaredTypeOfField, obj);
|
||||
} else {
|
||||
visitor.visitObjectField(fieldAttributes, declaredTypeOfField, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
61
src/org/mcteam/factions/gson/ObjectNavigatorFactory.java
Normal file
61
src/org/mcteam/factions/gson/ObjectNavigatorFactory.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* A factory class used to simplify {@link ObjectNavigator} creation.
|
||||
* This object holds on to a reference of the {@link ExclusionStrategy}
|
||||
* that you'd like to use with the {@link ObjectNavigator}.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ObjectNavigatorFactory {
|
||||
private final ExclusionStrategy strategy;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
|
||||
/**
|
||||
* Creates a factory object that will be able to create new
|
||||
* {@link ObjectNavigator}s with the provided {@code strategy}
|
||||
*
|
||||
* @param strategy the exclusion strategy to use with every instance that
|
||||
* is created by this factory instance.
|
||||
* @param fieldNamingPolicy the naming policy that should be applied to field
|
||||
* names
|
||||
*/
|
||||
public ObjectNavigatorFactory(ExclusionStrategy strategy, FieldNamingStrategy2 fieldNamingPolicy) {
|
||||
Preconditions.checkNotNull(fieldNamingPolicy);
|
||||
this.strategy = (strategy == null ? new NullExclusionStrategy() : strategy);
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ObjectNavigator} for this {@code srcObject},
|
||||
* {@code type} pair.
|
||||
*
|
||||
* @param objTypePair The object,type (fully genericized) being navigated
|
||||
* @return a new instance of a {@link ObjectNavigator} ready to navigate the
|
||||
* {@code srcObject} while taking into consideration the
|
||||
* {@code type}.
|
||||
*/
|
||||
public ObjectNavigator create(ObjectTypePair objTypePair) {
|
||||
return new ObjectNavigator(objTypePair, strategy);
|
||||
}
|
||||
|
||||
FieldNamingStrategy2 getFieldNamingPolicy() {
|
||||
return fieldNamingPolicy;
|
||||
}
|
||||
}
|
136
src/org/mcteam/factions/gson/ObjectTypePair.java
Normal file
136
src/org/mcteam/factions/gson/ObjectTypePair.java
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A holder class for an object and its type
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
final class ObjectTypePair {
|
||||
private Object obj;
|
||||
final Type type;
|
||||
private final boolean preserveType;
|
||||
|
||||
ObjectTypePair(Object obj, Type type, boolean preserveType) {
|
||||
this.obj = obj;
|
||||
this.type = type;
|
||||
this.preserveType = preserveType;
|
||||
}
|
||||
|
||||
Object getObject() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
void setObject(Object obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("preserveType: %b, type: %s, obj: %s", preserveType, type, obj);
|
||||
}
|
||||
|
||||
<HANDLER> Pair<HANDLER, ObjectTypePair> getMatchingHandler(
|
||||
ParameterizedTypeHandlerMap<HANDLER> handlers) {
|
||||
HANDLER handler = null;
|
||||
if (!preserveType && obj != null) {
|
||||
// First try looking up the handler for the actual type
|
||||
ObjectTypePair moreSpecificType = toMoreSpecificType();
|
||||
handler = handlers.getHandlerFor(moreSpecificType.type);
|
||||
if (handler != null) {
|
||||
return new Pair<HANDLER, ObjectTypePair>(handler, moreSpecificType);
|
||||
}
|
||||
}
|
||||
// Try the specified type
|
||||
handler = handlers.getHandlerFor(type);
|
||||
return handler == null ? null : new Pair<HANDLER, ObjectTypePair>(handler, this);
|
||||
}
|
||||
|
||||
ObjectTypePair toMoreSpecificType() {
|
||||
if (preserveType || obj == null) {
|
||||
return this;
|
||||
}
|
||||
Type actualType = getActualTypeIfMoreSpecific(type, obj.getClass());
|
||||
if (actualType == type) {
|
||||
return this;
|
||||
}
|
||||
return new ObjectTypePair(obj, actualType, preserveType);
|
||||
}
|
||||
|
||||
// This takes care of situations where the field was declared as an Object, but the
|
||||
// actual value contains something more specific. See Issue 54.
|
||||
// TODO (inder): This solution will not work if the field is of a generic type, but
|
||||
// the actual object is of a raw type (which is a sub-class of the generic type).
|
||||
static Type getActualTypeIfMoreSpecific(Type type, Class<?> actualClass) {
|
||||
if (type instanceof Class<?>) {
|
||||
Class<?> typeAsClass = (Class<?>) type;
|
||||
if (typeAsClass.isAssignableFrom(actualClass)) {
|
||||
type = actualClass;
|
||||
}
|
||||
if (type == Object.class) {
|
||||
type = actualClass;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Not using type.hashCode() since I am not sure if the subclasses of type reimplement
|
||||
// hashCode() to be equal for equal types
|
||||
return ((obj == null) ? 31 : obj.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ObjectTypePair other = (ObjectTypePair) obj;
|
||||
if (this.obj == null) {
|
||||
if (other.obj != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (this.obj != other.obj) { // Checking for reference equality
|
||||
return false;
|
||||
}
|
||||
if (type == null) {
|
||||
if (other.type != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!type.equals(other.type)) {
|
||||
return false;
|
||||
}
|
||||
return preserveType == other.preserveType;
|
||||
}
|
||||
|
||||
public boolean isPreserveType() {
|
||||
return preserveType;
|
||||
}
|
||||
}
|
62
src/org/mcteam/factions/gson/Pair.java
Normal file
62
src/org/mcteam/factions/gson/Pair.java
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
/**
|
||||
* A simple object that holds onto a pair of object references, first and second.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @param <FIRST>
|
||||
* @param <SECOND>
|
||||
*/
|
||||
final class Pair<FIRST, SECOND> {
|
||||
|
||||
final FIRST first;
|
||||
final SECOND second;
|
||||
|
||||
Pair(FIRST first, SECOND second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 17 * ((first != null) ? first.hashCode() : 0)
|
||||
+ 17 * ((second != null) ? second.hashCode() : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Pair<?, ?>)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Pair<?, ?> that = (Pair<?, ?>) o;
|
||||
return equal(this.first, that.first) && equal(this.second, that.second);
|
||||
}
|
||||
|
||||
private static boolean equal(Object a, Object b) {
|
||||
return a == b || (a != null && a.equals(b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{%s,%s}", first, second);
|
||||
}
|
||||
}
|
200
src/org/mcteam/factions/gson/ParameterizedTypeHandlerMap.java
Normal file
200
src/org/mcteam/factions/gson/ParameterizedTypeHandlerMap.java
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A map that provides ability to associate handlers for a specific type or all
|
||||
* of its sub-types
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @param <T> The handler that will be looked up by type
|
||||
*/
|
||||
final class ParameterizedTypeHandlerMap<T> {
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ParameterizedTypeHandlerMap.class.getName());
|
||||
private final Map<Type, T> map = new HashMap<Type, T>();
|
||||
private final List<Pair<Class<?>, T>> typeHierarchyList = new ArrayList<Pair<Class<?>, T>>();
|
||||
private boolean modifiable = true;
|
||||
|
||||
public synchronized void registerForTypeHierarchy(Class<?> typeOfT, T value) {
|
||||
Pair<Class<?>, T> pair = new Pair<Class<?>, T>(typeOfT, value);
|
||||
registerForTypeHierarchy(pair);
|
||||
}
|
||||
|
||||
public synchronized void registerForTypeHierarchy(Pair<Class<?>, T> pair) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(pair.first);
|
||||
if (index >= 0) {
|
||||
logger.log(Level.WARNING, "Overriding the existing type handler for {0}", pair.first);
|
||||
typeHierarchyList.remove(index);
|
||||
}
|
||||
index = getIndexOfAnOverriddenHandler(pair.first);
|
||||
if (index >= 0) {
|
||||
throw new IllegalArgumentException("The specified type handler for type " + pair.first
|
||||
+ " hides the previously registered type hierarchy handler for "
|
||||
+ typeHierarchyList.get(index).first + ". Gson does not allow this.");
|
||||
}
|
||||
// We want stack behavior for adding to this list. A type adapter added subsequently should
|
||||
// override a previously registered one.
|
||||
typeHierarchyList.add(0, pair);
|
||||
}
|
||||
|
||||
private int getIndexOfAnOverriddenHandler(Class<?> type) {
|
||||
for (int i = typeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = typeHierarchyList.get(i);
|
||||
if (type.isAssignableFrom(entry.first)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized void register(Type typeOfT, T value) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
if (hasSpecificHandlerFor(typeOfT)) {
|
||||
logger.log(Level.WARNING, "Overriding the existing type handler for {0}", typeOfT);
|
||||
}
|
||||
map.put(typeOfT, value);
|
||||
}
|
||||
|
||||
public synchronized void registerIfAbsent(ParameterizedTypeHandlerMap<T> other) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
for (Map.Entry<Type, T> entry : other.map.entrySet()) {
|
||||
if (!map.containsKey(entry.getKey())) {
|
||||
register(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
// Quite important to traverse the typeHierarchyList from stack bottom first since
|
||||
// we want to register the handlers in the same order to preserve priority order
|
||||
for (int i = other.typeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = other.typeHierarchyList.get(i);
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first);
|
||||
if (index < 0) {
|
||||
registerForTypeHierarchy(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void registerIfAbsent(Type typeOfT, T value) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
if (!map.containsKey(typeOfT)) {
|
||||
register(typeOfT, value);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void makeUnmodifiable() {
|
||||
modifiable = false;
|
||||
}
|
||||
|
||||
public synchronized T getHandlerFor(Type type) {
|
||||
T handler = map.get(type);
|
||||
if (handler == null) {
|
||||
Class<?> rawClass = TypeUtils.toRawClass(type);
|
||||
if (rawClass != type) {
|
||||
handler = getHandlerFor(rawClass);
|
||||
}
|
||||
if (handler == null) {
|
||||
// check if something registered for type hierarchy
|
||||
handler = getHandlerForTypeHierarchy(rawClass);
|
||||
}
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
private T getHandlerForTypeHierarchy(Class<?> type) {
|
||||
for (Pair<Class<?>, T> entry : typeHierarchyList) {
|
||||
if (entry.first.isAssignableFrom(type)) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized boolean hasSpecificHandlerFor(Type type) {
|
||||
return map.containsKey(type);
|
||||
}
|
||||
|
||||
private synchronized int getIndexOfSpecificHandlerForTypeHierarchy(Class<?> type) {
|
||||
for (int i = typeHierarchyList.size()-1; i >= 0; --i) {
|
||||
if (type.equals(typeHierarchyList.get(i).first)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized ParameterizedTypeHandlerMap<T> copyOf() {
|
||||
ParameterizedTypeHandlerMap<T> copy = new ParameterizedTypeHandlerMap<T>();
|
||||
for (Map.Entry<Type, T> entry : map.entrySet()) {
|
||||
copy.register(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Pair<Class<?>, T> entry : typeHierarchyList) {
|
||||
copy.registerForTypeHierarchy(entry);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{mapForTypeHierarchy:{");
|
||||
boolean first = true;
|
||||
for (Pair<Class<?>, T> entry : typeHierarchyList) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(typeToString(entry.first)).append(':');
|
||||
sb.append(entry.second);
|
||||
}
|
||||
sb.append("},map:{");
|
||||
first = true;
|
||||
for (Map.Entry<Type, T> entry : map.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(typeToString(entry.getKey())).append(':');
|
||||
sb.append(entry.getValue());
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String typeToString(Type type) {
|
||||
return TypeUtils.toRawClass(type).getSimpleName();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user