Now mcore2
This commit is contained in:
65
src/com/massivecraft/mcore2/InternalListener.java
Normal file
65
src/com/massivecraft/mcore2/InternalListener.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package com.massivecraft.mcore2;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerPreLoginEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
|
||||
import com.massivecraft.mcore2.persist.IClassManager;
|
||||
import com.massivecraft.mcore2.persist.Persist;
|
||||
import com.massivecraft.mcore2.util.PlayerUtil;
|
||||
|
||||
public class InternalListener implements Listener
|
||||
{
|
||||
MCore p;
|
||||
|
||||
public InternalListener(MCore p)
|
||||
{
|
||||
this.p = p;
|
||||
Bukkit.getServer().getPluginManager().registerEvents(this, this.p);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerPreLogin(PlayerPreLoginEvent event)
|
||||
{
|
||||
String id = event.getName();
|
||||
|
||||
PlayerUtil.getAllVisitorNames().add(id);
|
||||
|
||||
for (Persist realm : MCore.getPersistInstances().values())
|
||||
{
|
||||
for (IClassManager<?> manager : realm.getClassManagers().values())
|
||||
{
|
||||
if (manager.idCanFix(Player.class) == false) continue;
|
||||
if (manager.containsId(id)) continue;
|
||||
manager.create(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event)
|
||||
{
|
||||
if (event.isCancelled()) return;
|
||||
if (MCore.handleCommand(event.getPlayer(), event.getMessage().substring(1), false))
|
||||
{
|
||||
Bukkit.getLogger().info("[PLAYER_COMMAND] "+event.getPlayer().getName()+": "+event.getMessage());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private final static String refCommand = "mcoresilenteater";
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onServerCommand(ServerCommandEvent event)
|
||||
{
|
||||
if (event.getCommand().length() == 0) return;
|
||||
if (MCore.handleCommand(event.getSender(), event.getCommand(), false))
|
||||
{
|
||||
event.setCommand(refCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/com/massivecraft/mcore2/Lang.java
Normal file
11
src/com/massivecraft/mcore2/Lang.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.massivecraft.mcore2;
|
||||
|
||||
public class Lang
|
||||
{
|
||||
public static final String permForbidden = "<b>You don't have permission to %s.";
|
||||
public static final String permDoThat = "do that";
|
||||
|
||||
public static final String commandSenderMustBePlayer = "<b>This command can only be used by ingame players.";
|
||||
public static final String commandToFewArgs = "<b>To few arguments. <i>Use like this:";
|
||||
public static final String commandToManyArgs = "<b>Strange argument \"<p>%s<b>\". <i>Use the command like this:";
|
||||
}
|
||||
160
src/com/massivecraft/mcore2/MCore.java
Normal file
160
src/com/massivecraft/mcore2/MCore.java
Normal file
@@ -0,0 +1,160 @@
|
||||
package com.massivecraft.mcore2;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.massivecraft.mcore2.cmd.Cmd;
|
||||
import com.massivecraft.mcore2.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore2.persist.One;
|
||||
import com.massivecraft.mcore2.persist.Persist;
|
||||
import com.massivecraft.mcore2.util.LibLoader;
|
||||
import com.massivecraft.mcore2.util.PlayerUtil;
|
||||
import com.massivecraft.mcore2.util.Txt;
|
||||
|
||||
public class MCore extends JavaPlugin
|
||||
{
|
||||
InternalListener listener;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// PERSIST
|
||||
// -------------------------------------------- //
|
||||
private static Map<Object, Persist> persistInstances = new HashMap<Object, Persist>();
|
||||
public static Map<Object, Persist> getPersistInstances() { return persistInstances; }
|
||||
public static Persist getPersist(Object owner) { return persistInstances.get(owner); }
|
||||
public static void removePersist(Object owner) { persistInstances.remove(owner); }
|
||||
public static void createPersist(Object owner)
|
||||
{
|
||||
if (persistInstances.containsKey(owner)) return;
|
||||
persistInstances.put(owner, new Persist());
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CMD
|
||||
// -------------------------------------------- //
|
||||
private static Map<Object, Cmd> cmdInstances = new HashMap<Object, Cmd>();
|
||||
public static Map<Object, Cmd> getCmdInstances() { return cmdInstances; }
|
||||
public static Cmd getCmd(Object owner) { return cmdInstances.get(owner); }
|
||||
public static void removeCmd(Object owner) { cmdInstances.remove(owner); }
|
||||
public static void createCmd(Object owner)
|
||||
{
|
||||
if (cmdInstances.containsKey(owner)) return;
|
||||
cmdInstances.put(owner, new Cmd());
|
||||
}
|
||||
public static boolean handleCommand(CommandSender sender, String commandString, boolean testOnly)
|
||||
{
|
||||
List<String> args = new ArrayList<String>(Arrays.asList(commandString.split("\\s+")));
|
||||
if (args.size() == 0) return false;
|
||||
String alias = args.get(0);
|
||||
args.remove(0);
|
||||
for (Cmd cmd : cmdInstances.values())
|
||||
{
|
||||
if (cmd.handleCommand(sender, alias, args, testOnly)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// ONE
|
||||
// -------------------------------------------- //
|
||||
private static Map<MPlugin, One> oneInstances = new HashMap<MPlugin, One>();
|
||||
public static Map<MPlugin, One> getOneInstances() { return oneInstances; }
|
||||
public static One getOne(MPlugin owner) { return oneInstances.get(owner); }
|
||||
public static void removeOne(MPlugin owner) { oneInstances.remove(owner); }
|
||||
public static void createOne(MPlugin owner)
|
||||
{
|
||||
if (oneInstances.containsKey(owner)) return;
|
||||
oneInstances.put(owner, new One(owner));
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// LIBLOADER
|
||||
// -------------------------------------------- //
|
||||
private static Map<MPlugin, LibLoader> libLoaderInstances = new HashMap<MPlugin, LibLoader>();
|
||||
public static Map<MPlugin, LibLoader> getLibLoaderInstances() { return libLoaderInstances; }
|
||||
public static LibLoader getLibLoader(MPlugin owner) { return libLoaderInstances.get(owner); }
|
||||
public static void removeLibLoader(MPlugin owner) { libLoaderInstances.remove(owner); }
|
||||
public static void createLibLoader(MPlugin owner)
|
||||
{
|
||||
if (libLoaderInstances.containsKey(owner)) return;
|
||||
libLoaderInstances.put(owner, new LibLoader(owner));
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// DERP
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static Random random = new Random();
|
||||
|
||||
public MCore()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable()
|
||||
{
|
||||
// Avoid memleak by clearing ???
|
||||
// Or will this trigger errors???
|
||||
//Persist.getRealms().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable()
|
||||
{
|
||||
logPrefix = "["+this.getDescription().getName()+"] ";
|
||||
|
||||
PlayerUtil.populateAllVisitorNames();
|
||||
|
||||
// This is safe since all plugins using Persist should bukkit-depend this plugin.
|
||||
getPersistInstances().clear();
|
||||
|
||||
// Register events
|
||||
this.listener = new InternalListener(this);
|
||||
}
|
||||
|
||||
public static GsonBuilder getGsonBuilder()
|
||||
{
|
||||
return new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.disableHtmlEscaping()
|
||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SPOUT INTEGRATION
|
||||
// -------------------------------------------- //
|
||||
/*protected boolean spoutIsIntegrated = false;
|
||||
protected void integrateSpout()
|
||||
{
|
||||
if (spoutIsIntegrated) return;
|
||||
if ( ! Bukkit.getPluginManager().isPluginEnabled("Spout")) return;
|
||||
|
||||
// Ok we should be safe :) Lets integrate!
|
||||
this.spoutIsIntegrated = true;
|
||||
|
||||
|
||||
}*/
|
||||
|
||||
// -------------------------------------------- //
|
||||
// LOGGING
|
||||
// -------------------------------------------- //
|
||||
private static String logPrefix = null;
|
||||
public static void log(Object... msg)
|
||||
{
|
||||
log(Level.INFO, msg);
|
||||
}
|
||||
public static void log(Level level, Object... msg)
|
||||
{
|
||||
Logger.getLogger("Minecraft").log(level, logPrefix + Txt.implode(msg, " "));
|
||||
}
|
||||
}
|
||||
117
src/com/massivecraft/mcore2/MPlugin.java
Normal file
117
src/com/massivecraft/mcore2/MPlugin.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package com.massivecraft.mcore2;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.massivecraft.mcore2.cmd.Cmd;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore2.persist.One;
|
||||
import com.massivecraft.mcore2.persist.Persist;
|
||||
import com.massivecraft.mcore2.util.LibLoader;
|
||||
import com.massivecraft.mcore2.util.Txt;
|
||||
|
||||
|
||||
public abstract class MPlugin extends JavaPlugin
|
||||
{
|
||||
// Tools
|
||||
public Cmd cmd;
|
||||
public Persist persist;
|
||||
public One one;
|
||||
public LibLoader lib;
|
||||
|
||||
// Gson
|
||||
public Gson gson;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// ENABLE
|
||||
// -------------------------------------------- //
|
||||
|
||||
private long timeEnableStart;
|
||||
public boolean preEnable()
|
||||
{
|
||||
timeEnableStart = System.currentTimeMillis();
|
||||
this.logPrefix = "["+this.getDescription().getFullName()+"] ";
|
||||
log("=== ENABLE START ===");
|
||||
|
||||
// Ensure the base folder exists
|
||||
this.getDataFolder().mkdirs();
|
||||
|
||||
// Create Gson
|
||||
this.gson = this.getGsonBuilder().create();
|
||||
|
||||
// Create Tools
|
||||
MCore.createCmd(this);
|
||||
MCore.createPersist(this);
|
||||
MCore.createOne(this);
|
||||
MCore.createLibLoader(this);
|
||||
|
||||
// Assign tool pointers
|
||||
this.cmd = MCore.getCmd(this);
|
||||
this.persist = MCore.getPersist(this);
|
||||
this.one = MCore.getOne(this);
|
||||
this.lib = MCore.getLibLoader(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void postEnable()
|
||||
{
|
||||
log("=== ENABLE DONE (Took "+(System.currentTimeMillis()-timeEnableStart)+"ms) ===");
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// DISABLE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public void onDisable()
|
||||
{
|
||||
MCore.getPersist(this).saveAll();
|
||||
MCore.removePersist(this);
|
||||
MCore.removeOne(this);
|
||||
MCore.removeCmd(this);
|
||||
MCore.removeLibLoader(this);
|
||||
|
||||
this.cmd = null;
|
||||
this.persist = null;
|
||||
this.one = null;
|
||||
this.lib = null;
|
||||
|
||||
log("Disabled");
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// GSON
|
||||
// -------------------------------------------- //
|
||||
|
||||
public GsonBuilder getGsonBuilder()
|
||||
{
|
||||
return MCore.getGsonBuilder();
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONVENIENCE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public void suicide()
|
||||
{
|
||||
log("Now I suicide!");
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// LOGGING
|
||||
// -------------------------------------------- //
|
||||
private String logPrefix = null;
|
||||
public void log(Object... msg)
|
||||
{
|
||||
log(Level.INFO, msg);
|
||||
}
|
||||
public void log(Level level, Object... msg)
|
||||
{
|
||||
Logger.getLogger("Minecraft").log(level, this.logPrefix + Txt.implode(msg, " "));
|
||||
}
|
||||
}
|
||||
6
src/com/massivecraft/mcore2/Predictate.java
Normal file
6
src/com/massivecraft/mcore2/Predictate.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.massivecraft.mcore2;
|
||||
|
||||
public interface Predictate<T>
|
||||
{
|
||||
public boolean apply(T type);
|
||||
}
|
||||
62
src/com/massivecraft/mcore2/cmd/Cmd.java
Normal file
62
src/com/massivecraft/mcore2/cmd/Cmd.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package com.massivecraft.mcore2.cmd;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore2.cmd.arg.AHBoolean;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHDouble;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHFloat;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHInteger;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHMaterial;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHPlayer;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHWorld;
|
||||
import com.massivecraft.mcore2.cmd.arg.IArgHandler;
|
||||
|
||||
public class Cmd
|
||||
{
|
||||
protected Map<Class<?>, IArgHandler<?>> argHandlers = new HashMap<Class<?>, IArgHandler<?>>();
|
||||
public Map<Class<?>, IArgHandler<?>> getArgHandlers() { return this.argHandlers; }
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> IArgHandler<T> getArgHandler(Class<T> clazz) { return (IArgHandler<T>) this.argHandlers.get(clazz); }
|
||||
public <T> void setArgHandler(Class<T> clazz, IArgHandler<T> handler) { this.argHandlers.put(clazz, handler); }
|
||||
|
||||
protected Set<MCommand> commands = new HashSet<MCommand>();
|
||||
public Set<MCommand> getCommands() { return this.commands; }
|
||||
public void addCommand(MCommand mcommand) { this.commands.add(mcommand); }
|
||||
public MCommand getCommand(String alias)
|
||||
{
|
||||
for (MCommand command : this.commands)
|
||||
{
|
||||
if (command.aliases.contains(alias)) return command;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean handleCommand(CommandSender sender, String alias, List<String> args, boolean testOnly)
|
||||
{
|
||||
MCommand mcommand = this.getCommand(alias);
|
||||
if (mcommand == null) return false;
|
||||
if (testOnly) return true;
|
||||
mcommand.execute(sender, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Cmd()
|
||||
{
|
||||
this.setArgHandler(Boolean.class, new AHBoolean());
|
||||
this.setArgHandler(Double.class, new AHDouble());
|
||||
this.setArgHandler(Float.class, new AHFloat());
|
||||
this.setArgHandler(Integer.class, new AHInteger());
|
||||
this.setArgHandler(Material.class, new AHMaterial());
|
||||
this.setArgHandler(Player.class, new AHPlayer());
|
||||
this.setArgHandler(World.class, new AHWorld());
|
||||
}
|
||||
}
|
||||
57
src/com/massivecraft/mcore2/cmd/HelpCommand.java
Normal file
57
src/com/massivecraft/mcore2/cmd/HelpCommand.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package com.massivecraft.mcore2.cmd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
import com.massivecraft.mcore2.cmd.MCommand;
|
||||
import com.massivecraft.mcore2.util.Txt;
|
||||
|
||||
public class HelpCommand extends MCommand
|
||||
{
|
||||
private HelpCommand()
|
||||
{
|
||||
super();
|
||||
this.addAliases("?", "h", "help");
|
||||
this.setDesc("");
|
||||
this.addOptionalArg("page","1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform()
|
||||
{
|
||||
if (this.commandChain.size() == 0) return;
|
||||
MCommand parentCommand = this.commandChain.get(this.commandChain.size()-1);
|
||||
|
||||
ArrayList<String> lines = new ArrayList<String>();
|
||||
|
||||
for (String helpline : parentCommand.getHelp())
|
||||
{
|
||||
lines.add(Txt.parse("<a>#<i> "+helpline));
|
||||
}
|
||||
|
||||
for(MCommand subCommand : parentCommand.getSubCommands())
|
||||
{
|
||||
if (subCommand.visibleTo(sender))
|
||||
{
|
||||
lines.add(subCommand.getUseageTemplate(this.commandChain, true));
|
||||
}
|
||||
}
|
||||
|
||||
Integer pagenumber = this.argAs(0, Integer.class, 1);
|
||||
if (pagenumber == null) return;
|
||||
sendMessage(Txt.getPage(lines, pagenumber, "Help for command \""+parentCommand.getAliases().get(0)+"\""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MPlugin p()
|
||||
{
|
||||
if (this.commandChain.size() == 0) return null;
|
||||
return this.commandChain.get(this.commandChain.size()-1).p();
|
||||
}
|
||||
|
||||
private static HelpCommand instance = new HelpCommand();
|
||||
public static HelpCommand getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
493
src/com/massivecraft/mcore2/cmd/MCommand.java
Normal file
493
src/com/massivecraft/mcore2/cmd/MCommand.java
Normal file
@@ -0,0 +1,493 @@
|
||||
package com.massivecraft.mcore2.cmd;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore2.Lang;
|
||||
import com.massivecraft.mcore2.MCore;
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
import com.massivecraft.mcore2.cmd.arg.IArgHandler;
|
||||
import com.massivecraft.mcore2.cmd.req.IReq;
|
||||
import com.massivecraft.mcore2.cmd.req.ReqHasPerm;
|
||||
import com.massivecraft.mcore2.util.Perm;
|
||||
import com.massivecraft.mcore2.util.Txt;
|
||||
|
||||
public abstract class MCommand
|
||||
{
|
||||
public abstract MPlugin p();
|
||||
|
||||
// -------------------------------------------- //
|
||||
// COMMAND BEHAVIOR
|
||||
// -------------------------------------------- //
|
||||
|
||||
// FIELD: subCommands
|
||||
// The sub-commands to this command
|
||||
protected List<MCommand> subCommands;
|
||||
public List<MCommand> getSubCommands() { return this.subCommands; }
|
||||
public void setSubCommands(List<MCommand> val) { this.subCommands = val; }
|
||||
public void addSubCommand(MCommand subCommand)
|
||||
{
|
||||
subCommand.commandChain.addAll(this.commandChain);
|
||||
subCommand.commandChain.add(this);
|
||||
this.subCommands.add(subCommand);
|
||||
}
|
||||
|
||||
// FIELD: aliases
|
||||
// The different names this commands will react to
|
||||
protected List<String> aliases;
|
||||
public List<String> getAliases() { return this.aliases; }
|
||||
public void setAliases(List<String> val) { this.aliases = val; }
|
||||
public void addAliases(String... aliases) { this.aliases.addAll(Arrays.asList(aliases)); }
|
||||
public void addAliases(List<String> aliases) { this.aliases.addAll(aliases); }
|
||||
|
||||
// FIELD: requiredArgs
|
||||
// These args must always be sent
|
||||
protected List<String> requiredArgs;
|
||||
public List<String> getRequiredArgs() { return this.requiredArgs; }
|
||||
public void setRequiredArgs(List<String> val) { this.requiredArgs = val; }
|
||||
public void addRequiredArg(String arg) { this.requiredArgs.add(arg); }
|
||||
|
||||
// FIELD: optionalArgs
|
||||
// These args are optional
|
||||
protected Map<String, String> optionalArgs;
|
||||
public Map<String, String> getOptionalArgs() { return this.optionalArgs; }
|
||||
public void setOptionalArgs(Map<String, String> val) { this.optionalArgs = val; }
|
||||
public void addOptionalArg(String arg, String def) { this.optionalArgs.put(arg, def); }
|
||||
|
||||
// FIELD: errorOnToManyArgs
|
||||
// Should an error be thrown if "to many" args are sent.
|
||||
protected boolean errorOnToManyArgs;
|
||||
public boolean getErrorOnToManyArgs() { return this.errorOnToManyArgs; }
|
||||
public void setErrorOnToManyArgs(boolean val) { this.errorOnToManyArgs = val; }
|
||||
|
||||
// FIELD: requirements
|
||||
// All these requirements must be met for the command to be executable;
|
||||
protected List<IReq> requirements;
|
||||
public List<IReq> getRequirements() { return this.requirements; }
|
||||
public void setRequirements(List<IReq> val) { this.requirements = val; }
|
||||
public void addRequirements(IReq... requirements) { this.requirements.addAll(Arrays.asList(requirements)); }
|
||||
|
||||
// FIELD: desc
|
||||
// This field may be left blank and will in such case be loaded from the permissions node instead.
|
||||
// Thus make sure the permissions node description is an action description like "eat hamburgers" or "do admin stuff".
|
||||
protected String desc = null;
|
||||
public void setDesc(String val) { this.desc = val; }
|
||||
public String getDesc()
|
||||
{
|
||||
if (this.desc != null) return this.desc;
|
||||
|
||||
String perm = this.getDescPermission();
|
||||
if (perm != null)
|
||||
{
|
||||
String pdesc = Perm.getPermissionDescription(this.getDescPermission());
|
||||
if (pdesc != null)
|
||||
{
|
||||
return pdesc;
|
||||
}
|
||||
}
|
||||
|
||||
return "*info unavailable*";
|
||||
}
|
||||
|
||||
// FIELD: descPermission
|
||||
// This permission node IS NOT TESTED AT ALL. It is rather used in the method above.
|
||||
protected String descPermission;
|
||||
public String getDescPermission()
|
||||
{
|
||||
if (this.descPermission != null) return this.descPermission;
|
||||
// Otherwise we try to find one.
|
||||
for (IReq req : this.requirements)
|
||||
{
|
||||
if ( ! (req instanceof ReqHasPerm)) continue;
|
||||
return ((ReqHasPerm)req).getPerm();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public void setDescPermission(String val) { this.descPermission = val; }
|
||||
|
||||
// FIELD: help
|
||||
// This is a multi-line help text for the command.
|
||||
protected List<String> help = new ArrayList<String>();
|
||||
public void setHelp(List<String> val) { this.help = val; }
|
||||
public void setHelp(String... val) { this.help = Arrays.asList(val); }
|
||||
public List<String> getHelp() { return this.help; }
|
||||
|
||||
// FIELD: visibilityMode
|
||||
protected VisibilityMode visibilityMode;
|
||||
public VisibilityMode getVisibilityMode() { return this.visibilityMode; }
|
||||
public void setVisibilityMode(VisibilityMode val) { this.visibilityMode = val; }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// EXECUTION INFO
|
||||
// -------------------------------------------- //
|
||||
|
||||
// FIELD: args
|
||||
// Will contain the arguments, or and empty list if there are none.
|
||||
protected List<String> args;
|
||||
public List<String> getArgs() { return this.args; }
|
||||
public void setArgs(List<String> val) { this.args = val; }
|
||||
|
||||
// FIELD: commandChain
|
||||
// The command chain used to execute this command
|
||||
protected List<MCommand> commandChain = new ArrayList<MCommand>();
|
||||
public List<MCommand> getCommandChain() { return this.commandChain; }
|
||||
public void setCommandChain(List<MCommand> val) { this.commandChain = val; }
|
||||
|
||||
// FIELDS: sender, me, senderIsConsole
|
||||
public CommandSender sender;
|
||||
public Player me;
|
||||
public boolean senderIsConsole;
|
||||
|
||||
/*
|
||||
public boolean getSenderIsConsole() { return ! (this.sender instanceof Player); }
|
||||
public Player me()
|
||||
{
|
||||
if (sender instanceof Player)
|
||||
{
|
||||
return (Player) sender;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getSenderAs(Class<T> clazz)
|
||||
{
|
||||
if (clazz.isInstance(sender)) return (T) sender;
|
||||
|
||||
for (Persist realm : MCore.getPersistInstances().values())
|
||||
{
|
||||
for (IClassManager<?> manager : realm.getClassManagers().values())
|
||||
{
|
||||
if ( ! manager.getManagedClass().equals(clazz)) continue;
|
||||
if (manager.idCanFix(sender.getClass()) == false) continue;
|
||||
return (T) manager.get(sender);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}*/
|
||||
|
||||
public MCommand()
|
||||
{
|
||||
this.descPermission = null;
|
||||
|
||||
this.subCommands = new ArrayList<MCommand>();
|
||||
this.aliases = new ArrayList<String>();
|
||||
|
||||
this.requiredArgs = new ArrayList<String>();
|
||||
this.optionalArgs = new LinkedHashMap<String, String>();
|
||||
|
||||
this.requirements = new ArrayList<IReq>();
|
||||
|
||||
this.errorOnToManyArgs = true;
|
||||
|
||||
this.desc = null;
|
||||
|
||||
this.visibilityMode = VisibilityMode.VISIBLE;
|
||||
}
|
||||
|
||||
// The commandChain is a list of the parent command chain used to get to this command.
|
||||
public void execute(CommandSender sender, List<String> args, List<MCommand> commandChain)
|
||||
{
|
||||
// Set the execution-time specific variables
|
||||
this.sender = sender;
|
||||
this.senderIsConsole = true;
|
||||
this.me = null;
|
||||
if (sender instanceof Player)
|
||||
{
|
||||
this.me = (Player) sender;
|
||||
this.senderIsConsole = false;
|
||||
}
|
||||
|
||||
this.fixSenderVars();
|
||||
|
||||
this.args = args;
|
||||
this.commandChain = commandChain;
|
||||
|
||||
// Is there a matching sub command?
|
||||
if (args.size() > 0 )
|
||||
{
|
||||
for (MCommand subCommand: this.subCommands)
|
||||
{
|
||||
if (subCommand.aliases.contains(args.get(0)))
|
||||
{
|
||||
args.remove(0);
|
||||
commandChain.add(this);
|
||||
subCommand.execute(sender, args, commandChain);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! validCall(this.sender, this.args)) return;
|
||||
|
||||
perform();
|
||||
}
|
||||
|
||||
public void fixSenderVars() {};
|
||||
|
||||
public void execute(CommandSender sender, List<String> args)
|
||||
{
|
||||
execute(sender, args, new ArrayList<MCommand>());
|
||||
}
|
||||
|
||||
// This is where the command action is performed.
|
||||
public abstract void perform();
|
||||
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Call Validation
|
||||
// -------------------------------------------- //
|
||||
|
||||
/**
|
||||
* In this method we validate that all prerequisites to perform this command has been met.
|
||||
*/
|
||||
public boolean validCall(CommandSender sender, List<String> args)
|
||||
{
|
||||
if ( ! this.requirementsAreMet(sender, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! this.validArgs(args, sender))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visibleTo(CommandSender sender)
|
||||
{
|
||||
if (this.getVisibilityMode() == VisibilityMode.VISIBLE) return true;
|
||||
if (this.getVisibilityMode() == VisibilityMode.INVISIBLE) return false;
|
||||
return this.requirementsAreMet(sender, false);
|
||||
}
|
||||
|
||||
public boolean requirementsAreMet(CommandSender sender, boolean informSenderIfNot)
|
||||
{
|
||||
for (IReq req : this.getRequirements())
|
||||
{
|
||||
if ( ! req.test(sender, this))
|
||||
{
|
||||
if (informSenderIfNot)
|
||||
{
|
||||
this.msg(req.createErrorMessage(sender, this));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean validArgs(List<String> args, CommandSender sender)
|
||||
{
|
||||
if (args.size() < this.requiredArgs.size())
|
||||
{
|
||||
if (sender != null)
|
||||
{
|
||||
msg(Lang.commandToFewArgs);
|
||||
sender.sendMessage(this.getUseageTemplate());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.size() > this.requiredArgs.size() + this.optionalArgs.size() && this.errorOnToManyArgs)
|
||||
{
|
||||
if (sender != null)
|
||||
{
|
||||
// Get the to many string slice
|
||||
List<String> theToMany = args.subList(this.requiredArgs.size() + this.optionalArgs.size(), args.size());
|
||||
msg(Lang.commandToManyArgs, Txt.implode(theToMany, " "));
|
||||
sender.sendMessage(this.getUseageTemplate());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean validArgs(List<String> args)
|
||||
{
|
||||
return this.validArgs(args, null);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Help and Usage information
|
||||
// -------------------------------------------- //
|
||||
|
||||
public String getUseageTemplate(List<MCommand> commandChain, boolean addDesc)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
ret.append(Txt.parse("<c>"));
|
||||
ret.append('/');
|
||||
|
||||
for (MCommand mc : commandChain)
|
||||
{
|
||||
ret.append(Txt.implode(mc.aliases, ","));
|
||||
ret.append(' ');
|
||||
}
|
||||
|
||||
ret.append(Txt.implode(this.aliases, ","));
|
||||
|
||||
List<String> args = new ArrayList<String>();
|
||||
|
||||
for (String requiredArg : this.requiredArgs)
|
||||
{
|
||||
args.add("<"+requiredArg+">");
|
||||
}
|
||||
|
||||
for (Entry<String, String> optionalArg : this.optionalArgs.entrySet())
|
||||
{
|
||||
String val = optionalArg.getValue();
|
||||
if (val == null)
|
||||
{
|
||||
val = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
val = "="+val;
|
||||
}
|
||||
args.add("["+optionalArg.getKey()+val+"]");
|
||||
}
|
||||
|
||||
if (args.size() > 0)
|
||||
{
|
||||
ret.append(Txt.parse("<p>"));
|
||||
ret.append(' ');
|
||||
ret.append(Txt.implode(args, " "));
|
||||
}
|
||||
|
||||
if (addDesc)
|
||||
{
|
||||
ret.append(' ');
|
||||
ret.append(Txt.parse("<i>"));
|
||||
ret.append(this.getDesc());
|
||||
}
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
public String getUseageTemplate(boolean addDesc)
|
||||
{
|
||||
return getUseageTemplate(this.commandChain, addDesc);
|
||||
}
|
||||
|
||||
public String getUseageTemplate()
|
||||
{
|
||||
return getUseageTemplate(false);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Message Sending Helpers
|
||||
// -------------------------------------------- //
|
||||
|
||||
public void msg(String str, Object... args)
|
||||
{
|
||||
sender.sendMessage(Txt.parse(str, args));
|
||||
}
|
||||
|
||||
public void msg(String str)
|
||||
{
|
||||
sender.sendMessage(Txt.parse(str));
|
||||
}
|
||||
|
||||
public void msg(Collection<String> msgs)
|
||||
{
|
||||
for(String msg : msgs)
|
||||
{
|
||||
this.msg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(String msg)
|
||||
{
|
||||
sender.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void sendMessage(Collection<String> msgs)
|
||||
{
|
||||
for(String msg : msgs)
|
||||
{
|
||||
this.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// Argument Readers
|
||||
// -------------------------------------------- //
|
||||
|
||||
public String arg(int idx)
|
||||
{
|
||||
if ( ! this.argIsSet(idx)) return null;
|
||||
return this.args.get(idx);
|
||||
}
|
||||
|
||||
public boolean argIsSet(int idx)
|
||||
{
|
||||
if (this.args.size() < idx+1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized <T> T argAs(int idx, Class<T> clazz, String style, T defaultNotSet, T defaultNotFound)
|
||||
{
|
||||
if ( ! this.argIsSet(idx))
|
||||
{
|
||||
return defaultNotSet;
|
||||
}
|
||||
IArgHandler<T> handler = p().cmd.getArgHandler(clazz);
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
MCore.log(Level.SEVERE, "There is no ArgHandler for " + clazz.getName());
|
||||
}
|
||||
|
||||
T ret = handler.parse(this.arg(idx), style, this.sender, p());
|
||||
if (ret == null)
|
||||
{
|
||||
this.msg(handler.getErrors());
|
||||
return defaultNotFound;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public <T> T argAs(int idx, Class<T> clazz, T defaultNotSet, T defaultNotFound)
|
||||
{
|
||||
return this.argAs(idx, clazz, null, defaultNotSet, defaultNotFound);
|
||||
}
|
||||
|
||||
public <T> T argAs(int idx, Class<T> clazz, String style, T defaultNotSet)
|
||||
{
|
||||
return this.argAs(idx, clazz, style, defaultNotSet, null);
|
||||
}
|
||||
|
||||
public <T> T argAs(int idx, Class<T> clazz, T defaultNotSet)
|
||||
{
|
||||
return this.argAs(idx, clazz, null, defaultNotSet, null);
|
||||
}
|
||||
|
||||
public <T> T argAs(int idx, Class<T> clazz, String style)
|
||||
{
|
||||
return this.argAs(idx, clazz, style, null, null);
|
||||
}
|
||||
|
||||
public <T> T argAs(int idx, Class<T> clazz)
|
||||
{
|
||||
return this.argAs(idx, clazz, (T)null, null);
|
||||
}
|
||||
|
||||
public String argConcatFrom(int idx)
|
||||
{
|
||||
if ( ! this.argIsSet(idx)) return null;
|
||||
int from = idx;
|
||||
int to = args.size();
|
||||
if (to <= from) return "";
|
||||
return Txt.implode(args.subList(from, to), " ");
|
||||
}
|
||||
}
|
||||
9
src/com/massivecraft/mcore2/cmd/VisibilityMode.java
Normal file
9
src/com/massivecraft/mcore2/cmd/VisibilityMode.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.massivecraft.mcore2.cmd;
|
||||
|
||||
public enum VisibilityMode
|
||||
{
|
||||
VISIBLE, // Visible commands are visible to anyone. Even those who don't have permission to use it or is of invalid sender type.
|
||||
SECRET, // Secret commands are visible only to those who can use the command. These commands are usually some kind of admin commands.
|
||||
INVISIBLE, // Invisible commands are invisible to everyone, even those who can use the command.
|
||||
;
|
||||
}
|
||||
22
src/com/massivecraft/mcore2/cmd/arg/AHBase.java
Normal file
22
src/com/massivecraft/mcore2/cmd/arg/AHBase.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
|
||||
public abstract class AHBase<T> implements IArgHandler<T>
|
||||
{
|
||||
protected Collection<String> error = new ArrayList<String>();
|
||||
|
||||
@Override
|
||||
public abstract T parse(String str, String style, CommandSender sender, MPlugin p);
|
||||
|
||||
@Override
|
||||
public Collection<String> getErrors()
|
||||
{
|
||||
return this.error;
|
||||
}
|
||||
}
|
||||
21
src/com/massivecraft/mcore2/cmd/arg/AHBoolean.java
Normal file
21
src/com/massivecraft/mcore2/cmd/arg/AHBoolean.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
public class AHBoolean extends AHPrimitive<Boolean>
|
||||
{
|
||||
@Override
|
||||
protected String getPrimitiveName()
|
||||
{
|
||||
return "boolean";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean unsafeConvert(String str) throws Exception
|
||||
{
|
||||
str = str.toLowerCase();
|
||||
if (str.startsWith("y") || str.startsWith("t") || str.startsWith("on") || str.startsWith("+") || str.startsWith("1"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
16
src/com/massivecraft/mcore2/cmd/arg/AHDouble.java
Normal file
16
src/com/massivecraft/mcore2/cmd/arg/AHDouble.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
public class AHDouble extends AHPrimitive<Double>
|
||||
{
|
||||
@Override
|
||||
protected String getPrimitiveName()
|
||||
{
|
||||
return "double";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double unsafeConvert(String str) throws Exception
|
||||
{
|
||||
return Double.parseDouble(str);
|
||||
}
|
||||
}
|
||||
16
src/com/massivecraft/mcore2/cmd/arg/AHFloat.java
Normal file
16
src/com/massivecraft/mcore2/cmd/arg/AHFloat.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
public class AHFloat extends AHPrimitive<Float>
|
||||
{
|
||||
@Override
|
||||
protected String getPrimitiveName()
|
||||
{
|
||||
return "integer";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Float unsafeConvert(String str) throws Exception
|
||||
{
|
||||
return Float.parseFloat(str);
|
||||
}
|
||||
}
|
||||
16
src/com/massivecraft/mcore2/cmd/arg/AHInteger.java
Normal file
16
src/com/massivecraft/mcore2/cmd/arg/AHInteger.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
public class AHInteger extends AHPrimitive<Integer>
|
||||
{
|
||||
@Override
|
||||
protected String getPrimitiveName()
|
||||
{
|
||||
return "integer";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer unsafeConvert(String str) throws Exception
|
||||
{
|
||||
return Integer.parseInt(str);
|
||||
}
|
||||
}
|
||||
24
src/com/massivecraft/mcore2/cmd/arg/AHMaterial.java
Normal file
24
src/com/massivecraft/mcore2/cmd/arg/AHMaterial.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
|
||||
public class AHMaterial extends AHBase<Material>
|
||||
{
|
||||
@Override
|
||||
public Material parse(String str, String style, CommandSender sender, MPlugin p)
|
||||
{
|
||||
this.error.clear();
|
||||
Material ret = Material.matchMaterial(str);
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
this.error.add("<b>No material matching \"<p>"+str+"<b>\".");
|
||||
this.error.add("<i>Suggestion: <aqua>http://www.minecraftwiki.net/wiki/Data_values");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
39
src/com/massivecraft/mcore2/cmd/arg/AHPlayer.java
Normal file
39
src/com/massivecraft/mcore2/cmd/arg/AHPlayer.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
|
||||
public class AHPlayer extends AHBase<Player>
|
||||
{
|
||||
@Override
|
||||
public Player parse(String str, String style, CommandSender sender, MPlugin p)
|
||||
{
|
||||
this.error.clear();
|
||||
if (str == null) return null;
|
||||
|
||||
if (style != null && style.equals("match"))
|
||||
{
|
||||
List<Player> players = Bukkit.getServer().matchPlayer(str);
|
||||
if (players.size() > 0)
|
||||
{
|
||||
return players.get(0);
|
||||
}
|
||||
this.error.add("<b>No online player's name begins with \"<p>"+str+"<b>\".");
|
||||
}
|
||||
else
|
||||
{
|
||||
Player player = Bukkit.getServer().getPlayer(str);
|
||||
if (player != null)
|
||||
{
|
||||
return player;
|
||||
}
|
||||
this.error.add("<b>No player online with the exact name \"<p>"+str+"<b>\".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
58
src/com/massivecraft/mcore2/cmd/arg/AHPlayerWrapper.java
Normal file
58
src/com/massivecraft/mcore2/cmd/arg/AHPlayerWrapper.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
import com.massivecraft.mcore2.persist.IClassManager;
|
||||
import com.massivecraft.mcore2.persist.Persist;
|
||||
import com.massivecraft.mcore2.util.PlayerUtil;
|
||||
|
||||
public abstract class AHPlayerWrapper<T> extends AHBase<T>
|
||||
{
|
||||
public abstract Class<T> getClazz();
|
||||
|
||||
public IClassManager<T> getManager(MPlugin p)
|
||||
{
|
||||
return p.persist.getManager(getClazz());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T parse(String str, String style, CommandSender sender, MPlugin p)
|
||||
{
|
||||
this.error.clear();
|
||||
if (str == null) return null;
|
||||
|
||||
IClassManager<T> manager = this.getManager(p);
|
||||
T ret;
|
||||
|
||||
if (style != null && style.equalsIgnoreCase("match"))
|
||||
{
|
||||
ret = manager.getBestMatch(str);
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
this.error.add("<b>No player name begins with \"<p>"+str+"<b>\".");
|
||||
}
|
||||
else if (style != null && style.equalsIgnoreCase("matchany"))
|
||||
{
|
||||
ret = manager.get(Persist.getBestCIStart(PlayerUtil.getAllVisitorNames(), str));
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
this.error.add("<b>No player name begins with \"<p>"+str+"<b>\".");
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = manager.get(str);
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
|
||||
}
|
||||
this.error.add("<b>No player with the exact name \"<p>"+str+"<b>\".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
src/com/massivecraft/mcore2/cmd/arg/AHPrimitive.java
Normal file
29
src/com/massivecraft/mcore2/cmd/arg/AHPrimitive.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
|
||||
public abstract class AHPrimitive<T> extends AHBase<T>
|
||||
{
|
||||
protected abstract String getPrimitiveName();
|
||||
|
||||
protected abstract T unsafeConvert(String str) throws Exception;
|
||||
|
||||
@Override
|
||||
public T parse(String str, String style, CommandSender sender, MPlugin p)
|
||||
{
|
||||
this.error.clear();
|
||||
if (str == null) return null;
|
||||
try
|
||||
{
|
||||
T ret = this.unsafeConvert(str);
|
||||
return ret;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.error.add("<b>\"<p>"+str+"<b>\" is not a valid "+this.getPrimitiveName()+".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
26
src/com/massivecraft/mcore2/cmd/arg/AHWorld.java
Normal file
26
src/com/massivecraft/mcore2/cmd/arg/AHWorld.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
|
||||
public class AHWorld extends AHBase<World>
|
||||
{
|
||||
@Override
|
||||
public World parse(String str, String style, CommandSender sender, MPlugin p)
|
||||
{
|
||||
this.error.clear();
|
||||
if (str == null) return null;
|
||||
|
||||
World ret = Bukkit.getWorld(str);
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
this.error.add("<b>No world matching \"<p>"+str+"<b>\".");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
16
src/com/massivecraft/mcore2/cmd/arg/IArgHandler.java
Normal file
16
src/com/massivecraft/mcore2/cmd/arg/IArgHandler.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore2.cmd.arg;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.MPlugin;
|
||||
|
||||
public interface IArgHandler<T>
|
||||
{
|
||||
// Parse result returned - or null and something in the error message.
|
||||
public T parse(String str, String style, CommandSender sender, MPlugin p);
|
||||
|
||||
// Error here - or null.
|
||||
public Collection<String> getErrors();
|
||||
}
|
||||
14
src/com/massivecraft/mcore2/cmd/req/IReq.java
Normal file
14
src/com/massivecraft/mcore2/cmd/req/IReq.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.massivecraft.mcore2.cmd.req;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.cmd.MCommand;
|
||||
|
||||
public interface IReq
|
||||
{
|
||||
// This just tests wether the requirement is met or not.
|
||||
public boolean test(CommandSender sender, MCommand command);
|
||||
|
||||
// This just composes the error message and does NOT test the requirement at all.
|
||||
public String createErrorMessage(CommandSender sender, MCommand command);
|
||||
}
|
||||
31
src/com/massivecraft/mcore2/cmd/req/ReqHasPerm.java
Normal file
31
src/com/massivecraft/mcore2/cmd/req/ReqHasPerm.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.massivecraft.mcore2.cmd.req;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore2.cmd.MCommand;
|
||||
import com.massivecraft.mcore2.util.Perm;
|
||||
|
||||
public class ReqHasPerm implements IReq
|
||||
{
|
||||
private String perm;
|
||||
public String getPerm() { return this.perm; }
|
||||
public void setPerm(String val) { this.perm = val; }
|
||||
|
||||
public ReqHasPerm(String perm)
|
||||
{
|
||||
this.perm = perm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(CommandSender sender, MCommand command)
|
||||
{
|
||||
return sender.hasPermission(this.perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createErrorMessage(CommandSender sender, MCommand command)
|
||||
{
|
||||
return Perm.getForbiddenMessage(this.perm);
|
||||
}
|
||||
|
||||
}
|
||||
28
src/com/massivecraft/mcore2/cmd/req/ReqIsPlayer.java
Normal file
28
src/com/massivecraft/mcore2/cmd/req/ReqIsPlayer.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.massivecraft.mcore2.cmd.req;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore2.Lang;
|
||||
import com.massivecraft.mcore2.cmd.MCommand;
|
||||
|
||||
public class ReqIsPlayer implements IReq
|
||||
{
|
||||
@Override
|
||||
public boolean test(CommandSender sender, MCommand command)
|
||||
{
|
||||
return sender instanceof Player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createErrorMessage(CommandSender sender, MCommand command)
|
||||
{
|
||||
return Lang.commandSenderMustBePlayer;
|
||||
}
|
||||
|
||||
protected static ReqIsPlayer instance= new ReqIsPlayer();
|
||||
public static ReqIsPlayer getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
155
src/com/massivecraft/mcore2/gson/InventoryTypeAdapter.java
Normal file
155
src/com/massivecraft/mcore2/gson/InventoryTypeAdapter.java
Normal file
@@ -0,0 +1,155 @@
|
||||
package com.massivecraft.mcore2.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.getspout.spoutapi.SpoutManager;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializer;
|
||||
|
||||
public class InventoryTypeAdapter implements JsonDeserializer<Inventory>, JsonSerializer<Inventory>
|
||||
{
|
||||
private static Logger logger = Logger.getLogger(InventoryTypeAdapter.class.getName());
|
||||
private static final String SIZE = "size";
|
||||
private static final String TYPE = "type";
|
||||
private static final String AMOUNT = "amount";
|
||||
private static final String DAMAGE = "damage";
|
||||
private static final String ENCHANTMENTS = "enchantments";
|
||||
|
||||
@Override
|
||||
public Inventory deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
try
|
||||
{
|
||||
Collection<ItemStack> itemStacks = new ArrayList<ItemStack>();
|
||||
|
||||
JsonObject jsonInventory = json.getAsJsonObject();
|
||||
int size = jsonInventory.get(SIZE).getAsInt();
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
// Fetch the jsonItemStack or mark it as empty and continue
|
||||
String stackIdx = String.valueOf(i);
|
||||
if ( ! jsonInventory.has(stackIdx))
|
||||
{
|
||||
itemStacks.add(null);
|
||||
continue;
|
||||
}
|
||||
JsonObject jsonItemStack = jsonInventory.getAsJsonObject(stackIdx);
|
||||
|
||||
// Populate values
|
||||
int type = jsonItemStack.get(TYPE).getAsInt();
|
||||
int amount = 1;
|
||||
short damage = 0;
|
||||
|
||||
if (jsonItemStack.has(AMOUNT))
|
||||
{
|
||||
amount = jsonItemStack.get(AMOUNT).getAsInt();
|
||||
}
|
||||
|
||||
if (jsonItemStack.has(DAMAGE))
|
||||
{
|
||||
damage = jsonItemStack.get(DAMAGE).getAsShort();
|
||||
}
|
||||
|
||||
// Create Non enchanted stack
|
||||
ItemStack stack = new ItemStack(type, amount, damage);
|
||||
|
||||
// Add enchantments if there are any
|
||||
if (jsonItemStack.has(ENCHANTMENTS))
|
||||
{
|
||||
JsonObject jsonEnchantments = jsonItemStack.get(ENCHANTMENTS).getAsJsonObject();
|
||||
for (Entry<String, JsonElement> enchantmentEntry: jsonEnchantments.entrySet())
|
||||
{
|
||||
int enchantmentId = Integer.valueOf(enchantmentEntry.getKey());
|
||||
Integer enchantmentLevel = Integer.valueOf(enchantmentEntry.getValue().getAsString());
|
||||
stack.addEnchantment(Enchantment.getById(enchantmentId), enchantmentLevel);
|
||||
}
|
||||
}
|
||||
itemStacks.add(stack);
|
||||
}
|
||||
|
||||
return SpoutManager.getInventoryBuilder().construct(itemStacks, "");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
logger.warning("Error encountered while deserializing an inventory.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Inventory src, Type typeOfSrc, JsonSerializationContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonObject jsonInventory = new JsonObject();
|
||||
ItemStack[] itemStacks = src.getContents();
|
||||
jsonInventory.add(SIZE, new JsonPrimitive(itemStacks.length));
|
||||
|
||||
for (int i = 0; i < itemStacks.length; i++)
|
||||
{
|
||||
ItemStack itemStack = itemStacks[i];
|
||||
if (itemStack == null) continue;
|
||||
if (itemStack.getTypeId() == 0) continue;
|
||||
if (itemStack.getAmount() == 0) continue;
|
||||
JsonObject jsonItemStack = new JsonObject();
|
||||
|
||||
jsonItemStack.addProperty(TYPE, itemStack.getTypeId());
|
||||
if (itemStack.getAmount() != 1)
|
||||
{
|
||||
jsonItemStack.addProperty(AMOUNT, itemStack.getAmount());
|
||||
}
|
||||
if (itemStack.getDurability() != 0) // Durability is a weird name since it is the amount of damage.
|
||||
{
|
||||
jsonItemStack.addProperty(DAMAGE, itemStack.getDurability());
|
||||
}
|
||||
if (itemStack.getEnchantments().size() > 0)
|
||||
{
|
||||
JsonObject jsonEnchantments = new JsonObject();
|
||||
for (Entry<Enchantment, Integer> entry : itemStack.getEnchantments().entrySet())
|
||||
{
|
||||
jsonEnchantments.addProperty(String.valueOf(entry.getKey().getId()), entry.getValue());
|
||||
}
|
||||
jsonItemStack.add(ENCHANTMENTS, jsonEnchantments);
|
||||
}
|
||||
jsonInventory.add(String.valueOf(i), jsonItemStack);
|
||||
}
|
||||
return jsonInventory;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
logger.warning("Error encountered while serializing an inventory.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// This utility is nice to have in many cases :)
|
||||
public static boolean isInventoryEmpty(Inventory inv)
|
||||
{
|
||||
if (inv == null) return true;
|
||||
for (ItemStack stack : inv.getContents())
|
||||
{
|
||||
if (stack == null) continue;
|
||||
if (stack.getAmount() == 0) continue;
|
||||
if (stack.getTypeId() == 0) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.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());
|
||||
}
|
||||
}
|
||||
43
src/com/massivecraft/mcore2/lib/gson/Cache.java
Normal file
43
src/com/massivecraft/mcore2/lib/gson/Cache.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.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);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
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) {
|
||||
$Gson$Preconditions.checkNotNull(separatorString);
|
||||
$Gson$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();
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
}
|
||||
122
src/com/massivecraft/mcore2/lib/gson/DefaultTypeAdapters.java
Normal file
122
src/com/massivecraft/mcore2/lib/gson/DefaultTypeAdapters.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
/**
|
||||
* This type adapter supports three subclasses of date: Date, Timestamp, and
|
||||
* java.sql.Date.
|
||||
*/
|
||||
static final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
|
||||
private final DateFormat enUsFormat;
|
||||
private final DateFormat localFormat;
|
||||
private final DateFormat iso8601Format;
|
||||
|
||||
DefaultDateTypeAdapter() {
|
||||
this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
|
||||
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(String datePattern) {
|
||||
this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(int style) {
|
||||
this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
|
||||
}
|
||||
|
||||
public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
|
||||
this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
|
||||
DateFormat.getDateTimeInstance(dateStyle, timeStyle));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
|
||||
this.enUsFormat = enUsFormat;
|
||||
this.localFormat = localFormat;
|
||||
this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
// 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 (localFormat) {
|
||||
String dateFormatAsString = enUsFormat.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");
|
||||
}
|
||||
Date date = deserializeToDate(json);
|
||||
if (typeOfT == Date.class) {
|
||||
return date;
|
||||
} else if (typeOfT == Timestamp.class) {
|
||||
return new Timestamp(date.getTime());
|
||||
} else if (typeOfT == java.sql.Date.class) {
|
||||
return new java.sql.Date(date.getTime());
|
||||
} else {
|
||||
throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT);
|
||||
}
|
||||
}
|
||||
|
||||
private Date deserializeToDate(JsonElement json) {
|
||||
synchronized (localFormat) {
|
||||
try {
|
||||
return localFormat.parse(json.getAsString());
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
try {
|
||||
return enUsFormat.parse(json.getAsString());
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
try {
|
||||
return iso8601Format.parse(json.getAsString());
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(json.getAsString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(DefaultDateTypeAdapter.class.getSimpleName());
|
||||
sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
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;
|
||||
|
||||
DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) {
|
||||
this.strategies = $Gson$Preconditions.checkNotNull(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;
|
||||
}
|
||||
}
|
||||
109
src/com/massivecraft/mcore2/lib/gson/ExclusionStrategy.java
Normal file
109
src/com/massivecraft/mcore2/lib/gson/ExclusionStrategy.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.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>
|
||||
*
|
||||
* <p>For certain model classes, you may only want to serialize a field, but exclude it for
|
||||
* deserialization. To do that, you can write an {@code ExclusionStrategy} as per normal;
|
||||
* however, you would register it with the
|
||||
* {@link GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)} method.
|
||||
* For example:
|
||||
* <pre class="code">
|
||||
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .addDeserializationExclusionStrategy(excludeStrings)
|
||||
* .create();
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
|
||||
* @see GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)
|
||||
* @see GsonBuilder#addSerializationExclusionStrategy(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,38 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Excludes fields that do not have the {@link Expose} annotation
|
||||
*
|
||||
* @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,38 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Excludes fields that do not have the {@link Expose} annotation
|
||||
*
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
222
src/com/massivecraft/mcore2/lib/gson/FieldAttributes.java
Normal file
222
src/com/massivecraft/mcore2/lib/gson/FieldAttributes.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Pair;
|
||||
|
||||
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.google.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(Class<?> declaringClazz, Field f) {
|
||||
this.declaringClazz = $Gson$Preconditions.checkNotNull(declaringClazz);
|
||||
this.name = f.getName();
|
||||
this.declaredType = f.getType();
|
||||
this.isSynthetic = f.isSynthetic();
|
||||
this.modifiers = f.getModifiers();
|
||||
this.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);
|
||||
Collection<Annotation> cachedValue = ANNOTATION_CACHE.getElement(key);
|
||||
if (cachedValue == null) {
|
||||
cachedValue = Collections.unmodifiableCollection(
|
||||
Arrays.asList(field.getAnnotations()));
|
||||
ANNOTATION_CACHE.addElement(key, cachedValue);
|
||||
}
|
||||
annotations = cachedValue;
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @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/com/massivecraft/mcore2/lib/gson/FieldNamingPolicy.java
Normal file
99
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* An enumeration that defines a few standard naming conventions for JSON field names.
|
||||
* This enumeration should be used in conjunction with {@link com.massivecraft.mcore2.lib.gson.GsonBuilder}
|
||||
* to configure a {@link com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.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.
|
||||
*/
|
||||
public String translateName(FieldAttributes f);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
/**
|
||||
* Adapts the old FieldNamingStrategy to the new {@link FieldNamingStrategy2}
|
||||
* type.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 {
|
||||
private final FieldNamingStrategy adaptee;
|
||||
|
||||
FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) {
|
||||
this.adaptee = $Gson$Preconditions.checkNotNull(adaptee);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public String translateName(FieldAttributes f) {
|
||||
return adaptee.translateName(f.getFieldObject());
|
||||
}
|
||||
}
|
||||
804
src/com/massivecraft/mcore2/lib/gson/Gson.java
Normal file
804
src/com/massivecraft/mcore2/lib/gson/Gson.java
Normal file
@@ -0,0 +1,804 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ArrayTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.BigDecimalTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.BigIntegerTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.CollectionTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.DateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ExcludedTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonElementReader;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonElementWriter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.MapTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.MiniGson;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ObjectTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ReflectiveTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.SqlDateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TimeTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapters;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.MalformedJsonException;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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 com.massivecraft.mcore2.lib.gson.reflect.TypeToken
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class Gson {
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final ParameterizedTypeHandlerMap EMPTY_MAP =
|
||||
new ParameterizedTypeHandlerMap().makeUnmodifiable();
|
||||
|
||||
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(Modifier.TRANSIENT, Modifier.STATIC);
|
||||
static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY =
|
||||
new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy());
|
||||
|
||||
private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy();
|
||||
|
||||
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
|
||||
|
||||
private final ExclusionStrategy deserializationExclusionStrategy;
|
||||
private final ExclusionStrategy serializationExclusionStrategy;
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
/** 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;
|
||||
|
||||
private final MiniGson miniGson;
|
||||
|
||||
/**
|
||||
* 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 com.massivecraft.mcore2.lib.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 com.massivecraft.mcore2.lib.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>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Gson() {
|
||||
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
|
||||
EMPTY_MAP, false, EMPTY_MAP, EMPTY_MAP, false, DEFAULT_JSON_NON_EXECUTABLE, true,
|
||||
false, false, LongSerializationPolicy.DEFAULT,
|
||||
Collections.<TypeAdapter.Factory>emptyList());
|
||||
}
|
||||
|
||||
Gson(final ExclusionStrategy deserializationExclusionStrategy,
|
||||
final ExclusionStrategy serializationExclusionStrategy,
|
||||
final FieldNamingStrategy2 fieldNamingPolicy,
|
||||
final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
||||
final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
|
||||
boolean prettyPrinting, boolean serializeSpecialFloatingPointValues,
|
||||
LongSerializationPolicy longSerializationPolicy,
|
||||
List<TypeAdapter.Factory> typeAdapterFactories) {
|
||||
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
|
||||
this.serializationExclusionStrategy = serializationExclusionStrategy;
|
||||
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
this.generateNonExecutableJson = generateNonExecutableGson;
|
||||
this.htmlSafe = htmlSafe;
|
||||
this.prettyPrinting = prettyPrinting;
|
||||
|
||||
/*
|
||||
TODO: for serialization, honor:
|
||||
serializationExclusionStrategy
|
||||
fieldNamingPolicy
|
||||
serializeNulls
|
||||
serializers
|
||||
*/
|
||||
TypeAdapter.Factory reflectiveTypeAdapterFactory
|
||||
= new ReflectiveTypeAdapterFactory(constructorConstructor) {
|
||||
@Override
|
||||
public String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return fieldNamingPolicy.translateName(new FieldAttributes(declaringClazz, f));
|
||||
}
|
||||
@Override
|
||||
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
ExclusionStrategy strategy = Gson.this.serializationExclusionStrategy;
|
||||
return !strategy.shouldSkipClass(f.getType())
|
||||
&& !strategy.shouldSkipField(new FieldAttributes(declaringClazz, f));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
ExclusionStrategy strategy = Gson.this.deserializationExclusionStrategy;
|
||||
return !strategy.shouldSkipClass(f.getType())
|
||||
&& !strategy.shouldSkipField(new FieldAttributes(declaringClazz, f));
|
||||
}
|
||||
};
|
||||
|
||||
MiniGson.Builder builder = new MiniGson.Builder()
|
||||
.withoutDefaultFactories()
|
||||
.factory(TypeAdapters.STRING_FACTORY)
|
||||
.factory(TypeAdapters.INTEGER_FACTORY)
|
||||
.factory(TypeAdapters.BOOLEAN_FACTORY)
|
||||
.factory(TypeAdapters.BYTE_FACTORY)
|
||||
.factory(TypeAdapters.SHORT_FACTORY)
|
||||
.factory(TypeAdapters.newFactory(long.class, Long.class,
|
||||
longAdapter(longSerializationPolicy)))
|
||||
.factory(TypeAdapters.newFactory(double.class, Double.class,
|
||||
doubleAdapter(serializeSpecialFloatingPointValues)))
|
||||
.factory(TypeAdapters.newFactory(float.class, Float.class,
|
||||
floatAdapter(serializeSpecialFloatingPointValues)))
|
||||
.factory(new ExcludedTypeAdapterFactory(
|
||||
serializationExclusionStrategy, deserializationExclusionStrategy))
|
||||
.factory(TypeAdapters.NUMBER_FACTORY)
|
||||
.factory(TypeAdapters.CHARACTER_FACTORY)
|
||||
.factory(TypeAdapters.STRING_BUILDER_FACTORY)
|
||||
.factory(TypeAdapters.STRING_BUFFER_FACTORY)
|
||||
.typeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
|
||||
.typeAdapter(BigInteger.class, new BigIntegerTypeAdapter())
|
||||
.factory(TypeAdapters.JSON_ELEMENT_FACTORY)
|
||||
.factory(ObjectTypeAdapter.FACTORY);
|
||||
|
||||
for (TypeAdapter.Factory factory : typeAdapterFactories) {
|
||||
builder.factory(factory);
|
||||
}
|
||||
|
||||
builder
|
||||
.factory(new GsonToMiniGsonTypeAdapterFactory(this, serializers, deserializers))
|
||||
.factory(new CollectionTypeAdapterFactory(constructorConstructor))
|
||||
.factory(TypeAdapters.URL_FACTORY)
|
||||
.factory(TypeAdapters.URI_FACTORY)
|
||||
.factory(TypeAdapters.UUID_FACTORY)
|
||||
.factory(TypeAdapters.LOCALE_FACTORY)
|
||||
.factory(TypeAdapters.INET_ADDRESS_FACTORY)
|
||||
.factory(TypeAdapters.BIT_SET_FACTORY)
|
||||
.factory(DateTypeAdapter.FACTORY)
|
||||
.factory(TypeAdapters.CALENDAR_FACTORY)
|
||||
.factory(TimeTypeAdapter.FACTORY)
|
||||
.factory(SqlDateTypeAdapter.FACTORY)
|
||||
.factory(TypeAdapters.TIMESTAMP_FACTORY)
|
||||
.factory(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization))
|
||||
.factory(ArrayTypeAdapter.FACTORY)
|
||||
.factory(TypeAdapters.ENUM_FACTORY)
|
||||
.factory(reflectiveTypeAdapterFactory);
|
||||
|
||||
this.miniGson = builder.build();
|
||||
}
|
||||
|
||||
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
|
||||
if (serializeSpecialFloatingPointValues) {
|
||||
return TypeAdapters.DOUBLE;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Double read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return reader.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
double doubleValue = value.doubleValue();
|
||||
checkValidFloatingPoint(doubleValue);
|
||||
writer.value(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) {
|
||||
if (serializeSpecialFloatingPointValues) {
|
||||
return TypeAdapters.FLOAT;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Float read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return (float) reader.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
float floatValue = value.floatValue();
|
||||
checkValidFloatingPoint(floatValue);
|
||||
writer.value(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void checkValidFloatingPoint(double value) {
|
||||
if (Double.isNaN(value) || Double.isInfinite(value)) {
|
||||
throw new IllegalArgumentException(value
|
||||
+ " is not a valid double value as per JSON specification. To override this"
|
||||
+ " behavior, use GsonBuilder.serializeSpecialDoubleValues() method.");
|
||||
}
|
||||
}
|
||||
|
||||
private TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) {
|
||||
if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) {
|
||||
return TypeAdapters.LONG;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return reader.nextLong();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
writer.value(value.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ExclusionStrategy createExclusionStrategy() {
|
||||
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);
|
||||
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.INSTANCE;
|
||||
}
|
||||
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 com.massivecraft.mcore2.lib.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
|
||||
*/
|
||||
// the caller is required to make src and typeOfSrc consistent
|
||||
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
|
||||
JsonElementWriter writer = new JsonElementWriter();
|
||||
toJson(src, typeOfSrc, writer);
|
||||
return writer.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 toJson(JsonNull.INSTANCE);
|
||||
}
|
||||
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 com.massivecraft.mcore2.lib.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(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 {
|
||||
if (src != null) {
|
||||
toJson(src, src.getClass(), writer);
|
||||
} else {
|
||||
toJson(JsonNull.INSTANCE, writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 com.massivecraft.mcore2.lib.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 {
|
||||
try {
|
||||
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
|
||||
toJson(src, typeOfSrc, jsonWriter);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
|
||||
TypeAdapter<?> adapter = miniGson.getAdapter(TypeToken.get(typeOfSrc));
|
||||
boolean oldLenient = writer.isLenient();
|
||||
writer.setLenient(true);
|
||||
boolean oldHtmlSafe = writer.isHtmlSafe();
|
||||
writer.setHtmlSafe(htmlSafe);
|
||||
boolean oldSerializeNulls = writer.getSerializeNulls();
|
||||
writer.setSerializeNulls(serializeNulls);
|
||||
try {
|
||||
((TypeAdapter<Object>) adapter).write(writer, src);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
} finally {
|
||||
writer.setLenient(oldLenient);
|
||||
writer.setHtmlSafe(oldHtmlSafe);
|
||||
writer.setSerializeNulls(oldSerializeNulls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
|
||||
toJson(jsonElement, jsonWriter);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new JSON writer configured for this GSON and with the non-execute
|
||||
* prefix if that is configured.
|
||||
*/
|
||||
private JsonWriter newJsonWriter(Writer writer) throws IOException {
|
||||
if (generateNonExecutableJson) {
|
||||
writer.write(JSON_NON_EXECUTABLE_PREFIX);
|
||||
}
|
||||
JsonWriter jsonWriter = new JsonWriter(writer);
|
||||
if (prettyPrinting) {
|
||||
jsonWriter.setIndent(" ");
|
||||
}
|
||||
jsonWriter.setSerializeNulls(serializeNulls);
|
||||
return jsonWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
boolean oldSerializeNulls = writer.getSerializeNulls();
|
||||
writer.setSerializeNulls(serializeNulls);
|
||||
try {
|
||||
Streams.write(jsonElement, writer);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
} finally {
|
||||
writer.setLenient(oldLenient);
|
||||
writer.setHtmlSafe(oldHtmlSafe);
|
||||
writer.setSerializeNulls(oldSerializeNulls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 com.massivecraft.mcore2.lib.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 com.massivecraft.mcore2.lib.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
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
||||
JsonReader jsonReader = new JsonReader(json);
|
||||
T object = (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 isEmpty = true;
|
||||
boolean oldLenient = reader.isLenient();
|
||||
reader.setLenient(true);
|
||||
try {
|
||||
reader.peek();
|
||||
isEmpty = false;
|
||||
TypeAdapter<T> typeAdapter = (TypeAdapter<T>) miniGson.getAdapter(TypeToken.get(typeOfT));
|
||||
return typeAdapter.read(reader);
|
||||
} catch (EOFException e) {
|
||||
/*
|
||||
* For compatibility with JSON 1.5 and earlier, we return null for empty
|
||||
* documents instead of throwing.
|
||||
*/
|
||||
if (isEmpty) {
|
||||
return null;
|
||||
}
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IllegalStateException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IOException e) {
|
||||
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
|
||||
throw new JsonSyntaxException(e);
|
||||
} 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 com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
return (T) fromJson(new JsonElementReader(json), typeOfT);
|
||||
}
|
||||
|
||||
@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(constructorConstructor)
|
||||
.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
717
src/com/massivecraft/mcore2/lib/gson/GsonBuilder.java
Normal file
717
src/com/massivecraft/mcore2/lib/gson/GsonBuilder.java
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapter;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <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())
|
||||
* .enableComplexMapKeySerialization()
|
||||
* .serializeNulls()
|
||||
* .setDateFormat(DateFormat.LONG)
|
||||
* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
|
||||
* .setPrettyPrinting()
|
||||
* .setVersion(1.0)
|
||||
* .create();
|
||||
* </pre></p>
|
||||
*
|
||||
* <p>NOTES:
|
||||
* <ul>
|
||||
* <li> the order of invocation of configuration methods does not matter.</li>
|
||||
* <li> The default serialization of {@link Date} and its subclasses in Gson does
|
||||
* not contain time-zone information. So, if you are using date/time instances,
|
||||
* use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class GsonBuilder {
|
||||
private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
|
||||
new InnerClassExclusionStrategy();
|
||||
private static final ExposeAnnotationDeserializationExclusionStrategy
|
||||
exposeAnnotationDeserializationExclusionStrategy =
|
||||
new ExposeAnnotationDeserializationExclusionStrategy();
|
||||
private static final ExposeAnnotationSerializationExclusionStrategy
|
||||
exposeAnnotationSerializationExclusionStrategy =
|
||||
new ExposeAnnotationSerializationExclusionStrategy();
|
||||
|
||||
private final Set<ExclusionStrategy> serializeExclusionStrategies =
|
||||
new HashSet<ExclusionStrategy>();
|
||||
private final Set<ExclusionStrategy> deserializeExclusionStrategies =
|
||||
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 final List<TypeAdapter.Factory> typeAdapterFactories
|
||||
= new ArrayList<TypeAdapter.Factory>();
|
||||
private boolean serializeNulls;
|
||||
private String datePattern;
|
||||
private int dateStyle;
|
||||
private int timeStyle;
|
||||
private boolean complexMapKeySerialization = false;
|
||||
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
|
||||
deserializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
deserializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
serializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
serializeExclusionStrategies.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 com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enabling this feature will only change the serialized form if the map key is
|
||||
* a complex type (i.e. non-primitive) in its <strong>serialized</strong> JSON
|
||||
* form. The default implementation of map serialization uses {@code toString()}
|
||||
* on the key; however, when this is called then one of the following cases
|
||||
* apply:
|
||||
*
|
||||
* <h3>Maps as JSON objects</h3>
|
||||
* For this case, assume that a type adapter is registered to serialize and
|
||||
* deserialize some {@code Point} class, which contains an x and y coordinate,
|
||||
* to/from the JSON Primitive string value {@code "(x,y)"}. The Java map would
|
||||
* then be serialized as a {@link JsonObject}.
|
||||
*
|
||||
* <p>Below is an example:
|
||||
* <pre> {@code
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .register(Point.class, new MyPointTypeAdapter())
|
||||
* .enableComplexMapKeySerialization()
|
||||
* .create();
|
||||
*
|
||||
* 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>
|
||||
*
|
||||
* <h3>Maps as JSON arrays</h3>
|
||||
* For this case, assume that a type adapter was NOT registered for some
|
||||
* {@code Point} class, but rather the default Gson serialization is applied.
|
||||
* In this case, some {@code new Point(2,3)} would serialize as {@code
|
||||
* {"x":2,"y":5}}.
|
||||
*
|
||||
* <p>Given the assumption above, a {@code Map<Point, String>} will be
|
||||
* serialize as an array of arrays (can be viewed as an entry set of pairs).
|
||||
*
|
||||
* <p>Below is an example of serializing complex types as JSON arrays:
|
||||
* <pre> {@code
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .enableComplexMapKeySerialization()
|
||||
* .create();
|
||||
*
|
||||
* 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));
|
||||
* }
|
||||
*
|
||||
* The JSON output would look as follows:
|
||||
* <pre> {@code
|
||||
* [
|
||||
* [
|
||||
* {
|
||||
* "x": 5,
|
||||
* "y": 6
|
||||
* },
|
||||
* "a"
|
||||
* ],
|
||||
* [
|
||||
* {
|
||||
* "x": 8,
|
||||
* "y": 8
|
||||
* },
|
||||
* "b"
|
||||
* ]
|
||||
* ]
|
||||
* }</pre>
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
public GsonBuilder enableComplexMapKeySerialization() {
|
||||
complexMapKeySerialization = 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) {
|
||||
List<ExclusionStrategy> strategyList = Arrays.asList(strategies);
|
||||
serializeExclusionStrategies.addAll(strategyList);
|
||||
deserializeExclusionStrategies.addAll(strategyList);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply the passed in exclusion strategy during serialization.
|
||||
* If this method is invoked numerous times with different exclusion strategy objects
|
||||
* then the exclusion strategies that were added will be applied as a disjunction rule.
|
||||
* This means that if one of the added exclusion strategies suggests that a field (or
|
||||
* class) should be skipped then that field (or object) is skipped during its
|
||||
* serialization.
|
||||
*
|
||||
* @param strategy an exclusion strategy to apply during serialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
|
||||
serializeExclusionStrategies.add(strategy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply the passed in exclusion strategy during deserialization.
|
||||
* If this method is invoked numerous times with different exclusion strategy objects
|
||||
* then the exclusion strategies that were added will be applied as a disjunction rule.
|
||||
* This means that if one of the added exclusion strategies suggests that a field (or
|
||||
* class) should be skipped then that field (or object) is skipped during its
|
||||
* deserialization.
|
||||
*
|
||||
* @param strategy an exclusion strategy to apply during deserialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
|
||||
deserializeExclusionStrategies.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>The date format will be used to serialize and deserialize {@link java.util.Date}, {@link
|
||||
* java.sql.Timestamp} and {@link java.sql.Date}.
|
||||
*
|
||||
* <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) {
|
||||
return registerTypeAdapter(type, typeAdapter, false);
|
||||
}
|
||||
|
||||
private GsonBuilder registerTypeAdapter(Type type, Object typeAdapter, boolean isSystem) {
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?>
|
||||
|| typeAdapter instanceof InstanceCreator<?>
|
||||
|| typeAdapter instanceof TypeAdapter.Factory);
|
||||
if (Primitives.isPrimitive(type) || Primitives.isWrapperType(type)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot register type adapters for " + type);
|
||||
}
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter, isSystem);
|
||||
}
|
||||
if (typeAdapter instanceof JsonSerializer<?>) {
|
||||
registerSerializer(type, (JsonSerializer<?>) typeAdapter, isSystem);
|
||||
}
|
||||
if (typeAdapter instanceof JsonDeserializer<?>) {
|
||||
registerDeserializer(type, (JsonDeserializer<?>) typeAdapter, isSystem);
|
||||
}
|
||||
if (typeAdapter instanceof TypeAdapter.Factory) {
|
||||
typeAdapterFactories.add((TypeAdapter.Factory) 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, boolean isSystem) {
|
||||
instanceCreators.register(typeOfT, instanceCreator, isSystem);
|
||||
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, JsonSerializer<T> serializer,
|
||||
boolean isSystem) {
|
||||
serializers.register(typeOfT, serializer, isSystem);
|
||||
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,
|
||||
boolean isSystem) {
|
||||
deserializers.register(typeOfT, new JsonDeserializerExceptionWrapper<T>(deserializer), isSystem);
|
||||
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
|
||||
*/
|
||||
public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
|
||||
return registerTypeHierarchyAdapter(baseType, typeAdapter, false);
|
||||
}
|
||||
|
||||
private GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter,
|
||||
boolean isSystem) {
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator<?>) typeAdapter, isSystem);
|
||||
}
|
||||
if (typeAdapter instanceof JsonSerializer<?>) {
|
||||
registerSerializerForTypeHierarchy(baseType, (JsonSerializer<?>) typeAdapter, isSystem);
|
||||
}
|
||||
if (typeAdapter instanceof JsonDeserializer<?>) {
|
||||
registerDeserializerForTypeHierarchy(baseType, (JsonDeserializer<?>) typeAdapter, isSystem);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerInstanceCreatorForTypeHierarchy(Class<?> classOfT,
|
||||
InstanceCreator<? extends T> instanceCreator, boolean isSystem) {
|
||||
instanceCreators.registerForTypeHierarchy(classOfT, instanceCreator, isSystem);
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerSerializerForTypeHierarchy(Class<?> classOfT,
|
||||
JsonSerializer<T> serializer, boolean isSystem) {
|
||||
serializers.registerForTypeHierarchy(classOfT, serializer, isSystem);
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerDeserializerForTypeHierarchy(Class<?> classOfT,
|
||||
JsonDeserializer<T> deserializer, boolean isSystem) {
|
||||
deserializers.registerForTypeHierarchy(classOfT,
|
||||
new JsonDeserializerExceptionWrapper<T>(deserializer), isSystem);
|
||||
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> deserializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(deserializeExclusionStrategies);
|
||||
List<ExclusionStrategy> serializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(serializeExclusionStrategies);
|
||||
deserializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
serializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
|
||||
if (!serializeInnerClasses) {
|
||||
deserializationStrategies.add(innerClassExclusionStrategy);
|
||||
serializationStrategies.add(innerClassExclusionStrategy);
|
||||
}
|
||||
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
|
||||
VersionExclusionStrategy versionExclusionStrategy =
|
||||
new VersionExclusionStrategy(ignoreVersionsAfter);
|
||||
deserializationStrategies.add(versionExclusionStrategy);
|
||||
serializationStrategies.add(versionExclusionStrategy);
|
||||
}
|
||||
if (excludeFieldsWithoutExposeAnnotation) {
|
||||
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
|
||||
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
|
||||
}
|
||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, serializers, deserializers);
|
||||
|
||||
return new Gson(new DisjunctionExclusionStrategy(deserializationStrategies),
|
||||
new DisjunctionExclusionStrategy(serializationStrategies),
|
||||
fieldNamingPolicy, instanceCreators.copyOf().makeUnmodifiable(), serializeNulls,
|
||||
serializers.copyOf().makeUnmodifiable(), deserializers.copyOf().makeUnmodifiable(),
|
||||
complexMapKeySerialization, generateNonExecutableJson, escapeHtmlChars, prettyPrinting,
|
||||
serializeSpecialFloatingPointValues, longSerializationPolicy, typeAdapterFactories);
|
||||
}
|
||||
|
||||
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) {
|
||||
registerIfAbsent(Date.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(Date.class, deserializers, dateTypeAdapter);
|
||||
registerIfAbsent(Timestamp.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(Timestamp.class, deserializers, dateTypeAdapter);
|
||||
registerIfAbsent(java.sql.Date.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(java.sql.Date.class, deserializers, dateTypeAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void registerIfAbsent(Class<?> type,
|
||||
ParameterizedTypeHandlerMap<T> adapters, T adapter) {
|
||||
if (!adapters.hasSpecificHandlerFor(type)) {
|
||||
adapters.register(type, adapter, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.MiniGson;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
final class GsonToMiniGsonTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final JsonDeserializationContext deserializationContext;
|
||||
private final JsonSerializationContext serializationContext;
|
||||
|
||||
public GsonToMiniGsonTypeAdapterFactory(final Gson gson,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers) {
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
|
||||
this.deserializationContext = new JsonDeserializationContext() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
return (T) gson.fromJson(json, typeOfT);
|
||||
}
|
||||
};
|
||||
|
||||
this.serializationContext = new JsonSerializationContext() {
|
||||
public JsonElement serialize(Object src) {
|
||||
return gson.toJsonTree(src);
|
||||
}
|
||||
public JsonElement serialize(Object src, Type typeOfSrc) {
|
||||
return gson.toJsonTree(src, typeOfSrc);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final MiniGson context, final TypeToken<T> typeToken) {
|
||||
final Type type = typeToken.getType();
|
||||
|
||||
@SuppressWarnings("unchecked") // guaranteed to match typeOfT
|
||||
final JsonSerializer<T> serializer
|
||||
= (JsonSerializer<T>) serializers.getHandlerFor(type, false);
|
||||
@SuppressWarnings("unchecked") // guaranteed to match typeOfT
|
||||
final JsonDeserializer<T> deserializer
|
||||
= (JsonDeserializer<T>) deserializers.getHandlerFor(type, false);
|
||||
|
||||
if (serializer == null && deserializer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
/**
|
||||
* The delegate is lazily created because it may not be needed, and
|
||||
* creating it may fail.
|
||||
*/
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (deserializer == null) {
|
||||
return delegate().read(reader);
|
||||
}
|
||||
JsonElement value = Streams.parse(reader);
|
||||
if (value.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
return deserializer.deserialize(value, type, deserializationContext);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (serializer == null) {
|
||||
delegate().write(writer, value);
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
JsonElement element = serializer.serialize(value, type, serializationContext);
|
||||
Streams.write(element, writer);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = context.getNextAdapter(GsonToMiniGsonTypeAdapterFactory.this, typeToken));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Strategy for excluding inner classes.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final 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/com/massivecraft/mcore2/lib/gson/InstanceCreator.java
Normal file
92
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.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);
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
}
|
||||
282
src/com/massivecraft/mcore2/lib/gson/JsonArray.java
Normal file
282
src/com/massivecraft/mcore2/lib/gson/JsonArray.java
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
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.INSTANCE;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return elements.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
88
src/com/massivecraft/mcore2/lib/gson/JsonDeserializer.java
Normal file
88
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.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 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
* throws JsonParseException {
|
||||
* return 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,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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
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
|
||||
*/
|
||||
final 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) {
|
||||
this.delegate = $Gson$Preconditions.checkNotNull(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 deserialize json object ")
|
||||
.append(json)
|
||||
.append(" given the type ")
|
||||
.append(typeOfT);
|
||||
throw new JsonParseException(errorMsg.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
}
|
||||
325
src/com/massivecraft/mcore2/lib/gson/JsonElement.java
Normal file
325
src/com/massivecraft/mcore2/lib/gson/JsonElement.java
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
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 {
|
||||
/**
|
||||
* 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("Not a JSON Object: " + this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representation of this element.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
jsonWriter.setLenient(true);
|
||||
Streams.write(this, jsonWriter);
|
||||
return stringWriter.toString();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/com/massivecraft/mcore2/lib/gson/JsonElementVisitor.java
Normal file
47
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
46
src/com/massivecraft/mcore2/lib/gson/JsonIOException.java
Normal file
46
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.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);
|
||||
}
|
||||
}
|
||||
58
src/com/massivecraft/mcore2/lib/gson/JsonNull.java
Normal file
58
src/com/massivecraft/mcore2/lib/gson/JsonNull.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* A class representing a Json {@code null} value.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @since 1.2
|
||||
*/
|
||||
public final class JsonNull extends JsonElement {
|
||||
/**
|
||||
* singleton for JsonNull
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public static final JsonNull INSTANCE = new JsonNull();
|
||||
|
||||
/**
|
||||
* Creates a new JsonNull object.
|
||||
* Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public JsonNull() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 this == other || other instanceof JsonNull;
|
||||
}
|
||||
}
|
||||
200
src/com/massivecraft/mcore2/lib/gson/JsonObject.java
Normal file
200
src/com/massivecraft/mcore2/lib/gson/JsonObject.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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
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 = new LinkedHashMap<String, JsonElement>();
|
||||
|
||||
/**
|
||||
* Creates an empty JsonObject.
|
||||
*/
|
||||
public JsonObject() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (value == null) {
|
||||
value = JsonNull.INSTANCE;
|
||||
}
|
||||
members.put($Gson$Preconditions.checkNotNull(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.INSTANCE : 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.INSTANCE : 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
|
||||
public boolean equals(Object o) {
|
||||
return (o == this) || (o instanceof JsonObject
|
||||
&& ((JsonObject) o).members.equals(members));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return members.hashCode();
|
||||
}
|
||||
}
|
||||
64
src/com/massivecraft/mcore2/lib/gson/JsonParseException.java
Normal file
64
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.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);
|
||||
}
|
||||
}
|
||||
99
src/com/massivecraft/mcore2/lib/gson/JsonParser.java
Normal file
99
src/com/massivecraft/mcore2/lib/gson/JsonParser.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.MalformedJsonException;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
/**
|
||||
* 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.INSTANCE;
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
json.setLenient(lenient);
|
||||
}
|
||||
}
|
||||
}
|
||||
336
src/com/massivecraft/mcore2/lib/gson/JsonPrimitive.java
Normal file
336
src/com/massivecraft/mcore2/lib/gson/JsonPrimitive.java
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.LazilyParsedNumber;
|
||||
|
||||
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 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 {
|
||||
$Gson$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}.
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
if (isBoolean()) {
|
||||
return getAsBooleanWrapper().booleanValue();
|
||||
} else {
|
||||
// Check to see if the value as a String is "true" in any case.
|
||||
return 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 NumberFormatException if the value contained is not a valid Number.
|
||||
*/
|
||||
@Override
|
||||
public Number getAsNumber() {
|
||||
return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@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 NumberFormatException 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 NumberFormatException 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 NumberFormatException 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 NumberFormatException 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 NumberFormatException 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);
|
||||
}
|
||||
|
||||
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 (value instanceof Number) {
|
||||
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 (value instanceof Number && other.value instanceof Number) {
|
||||
double a = getAsNumber().doubleValue();
|
||||
// Java standard types other than double return true for two NaN. So, need
|
||||
// special handling for double.
|
||||
double b = other.getAsNumber().doubleValue();
|
||||
return a == b || (Double.isNaN(a) && Double.isNaN(b));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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);
|
||||
}
|
||||
86
src/com/massivecraft/mcore2/lib/gson/JsonSerializer.java
Normal file
86
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.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 com.massivecraft.mcore2.lib.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 serialize(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/com/massivecraft/mcore2/lib/gson/JsonStreamParser.java
Normal file
123
src/com/massivecraft/mcore2/lib/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 com.massivecraft.mcore2.lib.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 com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.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();
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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);
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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 com.massivecraft.mcore2.lib.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());
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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();
|
||||
}
|
||||
}
|
||||
53
src/com/massivecraft/mcore2/lib/gson/LruCache.java
Normal file
53
src/com/massivecraft/mcore2/lib/gson/LruCache.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.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;
|
||||
|
||||
public LruCache(int maxCapacity) {
|
||||
super(maxCapacity, 0.7F, true);
|
||||
this.maxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
public synchronized void addElement(K key, V value) {
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
public synchronized V getElement(K key) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
|
||||
return size() > maxCapacity;
|
||||
}
|
||||
}
|
||||
@@ -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 com.massivecraft.mcore2.lib.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
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
|
||||
*/
|
||||
ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
|
||||
this.letterModifier = $Gson$Preconditions.checkNotNull(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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 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 Joel Leitch
|
||||
*/
|
||||
abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 {
|
||||
|
||||
public final String translateName(FieldAttributes f) {
|
||||
return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the specific string translation.
|
||||
*
|
||||
* @param target the string object that will be manipulation/translated
|
||||
* @param fieldType the actual type value of the field
|
||||
* @param annotations the annotations set on the field
|
||||
* @return the translated field name
|
||||
*/
|
||||
protected abstract String translateName(String target, Type fieldType, Collection<Annotation> annotations);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the
|
||||
* {@link com.massivecraft.mcore2.lib.gson.annotations.SerializedName} annotation is applied to a
|
||||
* field then this strategy will translate the name to the {@code
|
||||
* serializedName.value()}; otherwise it delegates to the wrapped
|
||||
* {@link FieldNamingStrategy2}.
|
||||
*
|
||||
* <p>
|
||||
* NOTE: this class performs JSON field name validation for any of the fields
|
||||
* marked with an {@code @SerializedName} annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see SerializedName
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 {
|
||||
private final FieldNamingStrategy2 delegate;
|
||||
|
||||
SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String translateName(FieldAttributes f) {
|
||||
SerializedName serializedName = f.getAnnotation(SerializedName.class);
|
||||
return serializedName == null ? delegate.translateName(f) : serializedName.value();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
final class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
|
||||
private final boolean skipSyntheticFields;
|
||||
|
||||
SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) {
|
||||
this.skipSyntheticFields = skipSyntheticFields;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return skipSyntheticFields && f.isSynthetic();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names consist of mixed
|
||||
* case letters starting with a capital and are separated by a particular
|
||||
* {@code separatorString}.
|
||||
*
|
||||
*<p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class StringWrapper {
|
||||
* public String AStringField = "abcd";
|
||||
* }
|
||||
*
|
||||
* UpperCamelCaseSeparatorNamingPolicy policy = new UpperCamelCaseSeparatorNamingPolicy("_");
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("AStringField"));
|
||||
*
|
||||
* assert("A_String_Field".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class UpperCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
|
||||
|
||||
public UpperCamelCaseSeparatorNamingPolicy(String separatorString) {
|
||||
super(new CamelCaseSeparatorNamingPolicy(separatorString),
|
||||
new ModifyFirstLetterNamingPolicy(ModifyFirstLetterNamingPolicy.LetterModifier.UPPER));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.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
|
||||
* upper case letters.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* UpperCaseNamingPolicy policy = new UpperCaseNamingPolicy();
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("INTEGERFIELD".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class UpperCaseNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
||||
return target.toUpperCase();
|
||||
}
|
||||
}
|
||||
29
src/com/massivecraft/mcore2/lib/gson/VersionConstants.java
Normal file
29
src/com/massivecraft/mcore2/lib/gson/VersionConstants.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* Class contain all constants for versioning support.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class VersionConstants {
|
||||
// Prevent instantiation
|
||||
private VersionConstants() { }
|
||||
|
||||
static final double IGNORE_VERSIONS = -1D;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Since;
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Until;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
/**
|
||||
* This strategy will exclude any files and/or class that are passed the
|
||||
* {@link #version} value.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class VersionExclusionStrategy implements ExclusionStrategy {
|
||||
private final double version;
|
||||
|
||||
VersionExclusionStrategy(double version) {
|
||||
$Gson$Preconditions.checkArgument(version >= 0.0D);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return !isValidVersion(f.getAnnotation(Since.class), f.getAnnotation(Until.class));
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class));
|
||||
}
|
||||
|
||||
private boolean isValidVersion(Since since, Until until) {
|
||||
return (isValidSince(since) && isValidUntil(until));
|
||||
}
|
||||
|
||||
private boolean isValidSince(Since annotation) {
|
||||
if (annotation != null) {
|
||||
double annotationVersion = annotation.value();
|
||||
if (annotationVersion > version) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidUntil(Until annotation) {
|
||||
if (annotation != null) {
|
||||
double annotationVersion = annotation.value();
|
||||
if (annotationVersion <= version) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
79
src/com/massivecraft/mcore2/lib/gson/annotations/Expose.java
Normal file
79
src/com/massivecraft/mcore2/lib/gson/annotations/Expose.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation that indicates this member should be exposed for JSON
|
||||
* serialization or deserialization.
|
||||
*
|
||||
* <p>This annotation has no effect unless you build {@link com.massivecraft.mcore2.lib.gson.Gson}
|
||||
* with a {@link com.massivecraft.mcore2.lib.gson.GsonBuilder} and invoke
|
||||
* {@link com.massivecraft.mcore2.lib.gson.GsonBuilder#excludeFieldsWithoutExposeAnnotation()}
|
||||
* method.</p>
|
||||
*
|
||||
* <p>Here is an example of how this annotation is meant to be used:
|
||||
* <p><pre>
|
||||
* public class User {
|
||||
* @Expose private String firstName;
|
||||
* @Expose(serialize = false) private String lastName;
|
||||
* @Expose (serialize = false, deserialize = false) private String emailAddress;
|
||||
* private String password;
|
||||
* }
|
||||
* </pre></p>
|
||||
* If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
|
||||
* methods will use the {@code password} field along-with {@code firstName}, {@code lastName},
|
||||
* and {@code emailAddress} for serialization and deserialization. However, if you created Gson
|
||||
* with {@code Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()}
|
||||
* then the {@code toJson()} and {@code fromJson()} methods of Gson will exclude the
|
||||
* {@code password} field. This is because the {@code password} field is not marked with the
|
||||
* {@code @Expose} annotation. Gson will also exclude {@code lastName} and {@code emailAddress}
|
||||
* from serialization since {@code serialize} is set to {@code false}. Similarly, Gson will
|
||||
* exclude {@code emailAddress} from deserialization since {@code deserialize} is set to false.
|
||||
*
|
||||
* <p>Note that another way to achieve the same effect would have been to just mark the
|
||||
* {@code password} field as {@code transient}, and Gson would have excluded it even with default
|
||||
* settings. The {@code @Expose} annotation is useful in a style of programming where you want to
|
||||
* explicitly specify all fields that should get considered for serialization or deserialization.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Expose {
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code true}.
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean serialize() default true;
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code true}.
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean deserialize() default true;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation that indicates this member should be serialized to JSON with
|
||||
* the provided name value as its field name.
|
||||
*
|
||||
* <p>This annotation will override any {@link com.massivecraft.mcore2.lib.gson.FieldNamingPolicy}, including
|
||||
* the default field naming policy, that may have been set on the {@link com.massivecraft.mcore2.lib.gson.Gson}
|
||||
* instance. A different naming policy can set using the {@code GsonBuilder} class. See
|
||||
* {@link com.massivecraft.mcore2.lib.gson.GsonBuilder#setFieldNamingPolicy(com.massivecraft.mcore2.lib.gson.FieldNamingPolicy)}
|
||||
* for more information.</p>
|
||||
*
|
||||
* <p>Here is an example of how this annotation is meant to be used:</p>
|
||||
* <pre>
|
||||
* public class SomeClassWithFields {
|
||||
* @SerializedName("name") private final String someField;
|
||||
* private final String someOtherField;
|
||||
*
|
||||
* public SomeClassWithFields(String a, String b) {
|
||||
* this.someField = a;
|
||||
* this.someOtherField = b;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>The following shows the output that is generated when serializing an instance of the
|
||||
* above example class:</p>
|
||||
* <pre>
|
||||
* SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b");
|
||||
* Gson gson = new Gson();
|
||||
* String jsonRepresentation = gson.toJson(objectToSerialize);
|
||||
* System.out.println(jsonRepresentation);
|
||||
*
|
||||
* ===== OUTPUT =====
|
||||
* {"name":"a","someOtherField":"b"}
|
||||
* </pre>
|
||||
*
|
||||
* <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p>
|
||||
*
|
||||
* @see com.massivecraft.mcore2.lib.gson.FieldNamingPolicy
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface SerializedName {
|
||||
|
||||
/**
|
||||
* @return the desired name of the field when it is serialized
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
61
src/com/massivecraft/mcore2/lib/gson/annotations/Since.java
Normal file
61
src/com/massivecraft/mcore2/lib/gson/annotations/Since.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 com.massivecraft.mcore2.lib.gson.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation that indicates the version number since a member or a type has been present.
|
||||
* This annotation is useful to manage versioning of your Json classes for a web-service.
|
||||
*
|
||||
* <p>
|
||||
* This annotation has no effect unless you build {@link com.massivecraft.mcore2.lib.gson.Gson} with a
|
||||
* {@link com.massivecraft.mcore2.lib.gson.GsonBuilder} and invoke
|
||||
* {@link com.massivecraft.mcore2.lib.gson.GsonBuilder#setVersion(double)} method.
|
||||
*
|
||||
* <p>Here is an example of how this annotation is meant to be used:</p>
|
||||
* <pre>
|
||||
* public class User {
|
||||
* private String firstName;
|
||||
* private String lastName;
|
||||
* @Since(1.0) private String emailAddress;
|
||||
* @Since(1.0) private String password;
|
||||
* @Since(1.1) private Address address;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
|
||||
* methods will use all the fields for serialization and deserialization. However, if you created
|
||||
* Gson with {@code Gson gson = new GsonBuilder().setVersion(1.0).create()} then the
|
||||
* {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code address} field
|
||||
* since it's version number is set to {@code 1.1}.</p>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
public @interface Since {
|
||||
/**
|
||||
* the value indicating a version number since this member
|
||||
* or type has been present.
|
||||
*/
|
||||
double value();
|
||||
}
|
||||
66
src/com/massivecraft/mcore2/lib/gson/annotations/Until.java
Normal file
66
src/com/massivecraft/mcore2/lib/gson/annotations/Until.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation that indicates the version number until a member or a type should be present.
|
||||
* Basically, if Gson is created with a version number that exceeds the value stored in the
|
||||
* {@code Until} annotation then the field will be ignored from the JSON output. This annotation
|
||||
* is useful to manage versioning of your JSON classes for a web-service.
|
||||
*
|
||||
* <p>
|
||||
* This annotation has no effect unless you build {@link com.massivecraft.mcore2.lib.gson.Gson} with a
|
||||
* {@link com.massivecraft.mcore2.lib.gson.GsonBuilder} and invoke
|
||||
* {@link com.massivecraft.mcore2.lib.gson.GsonBuilder#setVersion(double)} method.
|
||||
*
|
||||
* <p>Here is an example of how this annotation is meant to be used:</p>
|
||||
* <pre>
|
||||
* public class User {
|
||||
* private String firstName;
|
||||
* private String lastName;
|
||||
* @Until(1.1) private String emailAddress;
|
||||
* @Until(1.1) private String password;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
|
||||
* methods will use all the fields for serialization and deserialization. However, if you created
|
||||
* Gson with {@code Gson gson = new GsonBuilder().setVersion(1.2).create()} then the
|
||||
* {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code emailAddress}
|
||||
* and {@code password} fields from the example above, because the version number passed to the
|
||||
* GsonBuilder, {@code 1.2}, exceeds the version number set on the {@code Until} annotation,
|
||||
* {@code 1.1}, for those fields.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @since 1.3
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.TYPE})
|
||||
public @interface Until {
|
||||
|
||||
/**
|
||||
* the value indicating a version number until this member
|
||||
* or type should be ignored.
|
||||
*/
|
||||
double value();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* This package provides annotations that can be used with {@link com.massivecraft.mcore2.lib.gson.Gson}.
|
||||
*
|
||||
* @author Inderjeet Singh, Joel Leitch
|
||||
*/
|
||||
package com.massivecraft.mcore2.lib.gson.annotations;
|
||||
@@ -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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
/**
|
||||
* A simple utility class used to check method Preconditions.
|
||||
*
|
||||
* <pre>
|
||||
* public long divideBy(long value) {
|
||||
* Preconditions.checkArgument(value != 0);
|
||||
* return this.value / value;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class $Gson$Preconditions {
|
||||
public static <T> T checkNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
592
src/com/massivecraft/mcore2/lib/gson/internal/$Gson$Types.java
Normal file
592
src/com/massivecraft/mcore2/lib/gson/internal/$Gson$Types.java
Normal file
@@ -0,0 +1,592 @@
|
||||
/**
|
||||
* 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import static com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions.checkArgument;
|
||||
import static com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions.checkNotNull;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.GenericDeclaration;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Static methods for working with types.
|
||||
*
|
||||
* @author Bob Lee
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public final class $Gson$Types {
|
||||
static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
|
||||
|
||||
private $Gson$Types() {}
|
||||
|
||||
/**
|
||||
* Returns a new parameterized type, applying {@code typeArguments} to
|
||||
* {@code rawType} and enclosed by {@code ownerType}.
|
||||
*
|
||||
* @return a {@link java.io.Serializable serializable} parameterized type.
|
||||
*/
|
||||
public static ParameterizedType newParameterizedTypeWithOwner(
|
||||
Type ownerType, Type rawType, Type... typeArguments) {
|
||||
return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array type whose elements are all instances of
|
||||
* {@code componentType}.
|
||||
*
|
||||
* @return a {@link java.io.Serializable serializable} generic array type.
|
||||
*/
|
||||
public static GenericArrayType arrayOf(Type componentType) {
|
||||
return new GenericArrayTypeImpl(componentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type that represents an unknown type that extends {@code bound}.
|
||||
* For example, if {@code bound} is {@code CharSequence.class}, this returns
|
||||
* {@code ? extends CharSequence}. If {@code bound} is {@code Object.class},
|
||||
* this returns {@code ?}, which is shorthand for {@code ? extends Object}.
|
||||
*/
|
||||
public static WildcardType subtypeOf(Type bound) {
|
||||
return new WildcardTypeImpl(new Type[] { bound }, EMPTY_TYPE_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type that represents an unknown supertype of {@code bound}. For
|
||||
* example, if {@code bound} is {@code String.class}, this returns {@code ?
|
||||
* super String}.
|
||||
*/
|
||||
public static WildcardType supertypeOf(Type bound) {
|
||||
return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type that is functionally equal but not necessarily equal
|
||||
* according to {@link Object#equals(Object) Object.equals()}. The returned
|
||||
* type is {@link java.io.Serializable}.
|
||||
*/
|
||||
public static Type canonicalize(Type type) {
|
||||
if (type instanceof Class) {
|
||||
Class<?> c = (Class<?>) type;
|
||||
return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
|
||||
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType p = (ParameterizedType) type;
|
||||
return new ParameterizedTypeImpl(p.getOwnerType(),
|
||||
p.getRawType(), p.getActualTypeArguments());
|
||||
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
GenericArrayType g = (GenericArrayType) type;
|
||||
return new GenericArrayTypeImpl(g.getGenericComponentType());
|
||||
|
||||
} else if (type instanceof WildcardType) {
|
||||
WildcardType w = (WildcardType) type;
|
||||
return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
|
||||
|
||||
} else {
|
||||
// type is either serializable as-is or unsupported
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getRawType(Type type) {
|
||||
if (type instanceof Class<?>) {
|
||||
// type is a normal class.
|
||||
return (Class<?>) type;
|
||||
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
|
||||
// I'm not exactly sure why getRawType() returns Type instead of Class.
|
||||
// Neal isn't either but suspects some pathological case related
|
||||
// to nested classes exists.
|
||||
Type rawType = parameterizedType.getRawType();
|
||||
checkArgument(rawType instanceof Class);
|
||||
return (Class<?>) rawType;
|
||||
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
Type componentType = ((GenericArrayType)type).getGenericComponentType();
|
||||
return Array.newInstance(getRawType(componentType), 0).getClass();
|
||||
|
||||
} else if (type instanceof TypeVariable) {
|
||||
// we could use the variable's bounds, but that won't work if there are multiple.
|
||||
// having a raw type that's more general than necessary is okay
|
||||
return Object.class;
|
||||
|
||||
} else if (type instanceof WildcardType) {
|
||||
return getRawType(((WildcardType) type).getUpperBounds()[0]);
|
||||
|
||||
} else {
|
||||
String className = type == null ? "null" : type.getClass().getName();
|
||||
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
|
||||
+ "GenericArrayType, but <" + type + "> is of type " + className);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean equal(Object a, Object b) {
|
||||
return a == b || (a != null && a.equals(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@code a} and {@code b} are equal.
|
||||
*/
|
||||
public static boolean equals(Type a, Type b) {
|
||||
if (a == b) {
|
||||
// also handles (a == null && b == null)
|
||||
return true;
|
||||
|
||||
} else if (a instanceof Class) {
|
||||
// Class already specifies equals().
|
||||
return a.equals(b);
|
||||
|
||||
} else if (a instanceof ParameterizedType) {
|
||||
if (!(b instanceof ParameterizedType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: save a .clone() call
|
||||
ParameterizedType pa = (ParameterizedType) a;
|
||||
ParameterizedType pb = (ParameterizedType) b;
|
||||
return equal(pa.getOwnerType(), pb.getOwnerType())
|
||||
&& pa.getRawType().equals(pb.getRawType())
|
||||
&& Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
|
||||
|
||||
} else if (a instanceof GenericArrayType) {
|
||||
if (!(b instanceof GenericArrayType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GenericArrayType ga = (GenericArrayType) a;
|
||||
GenericArrayType gb = (GenericArrayType) b;
|
||||
return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
|
||||
|
||||
} else if (a instanceof WildcardType) {
|
||||
if (!(b instanceof WildcardType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WildcardType wa = (WildcardType) a;
|
||||
WildcardType wb = (WildcardType) b;
|
||||
return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())
|
||||
&& Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());
|
||||
|
||||
} else if (a instanceof TypeVariable) {
|
||||
if (!(b instanceof TypeVariable)) {
|
||||
return false;
|
||||
}
|
||||
TypeVariable<?> va = (TypeVariable<?>) a;
|
||||
TypeVariable<?> vb = (TypeVariable<?>) b;
|
||||
return va.getGenericDeclaration() == vb.getGenericDeclaration()
|
||||
&& va.getName().equals(vb.getName());
|
||||
|
||||
} else {
|
||||
// This isn't a type we support. Could be a generic array type, wildcard type, etc.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static int hashCodeOrZero(Object o) {
|
||||
return o != null ? o.hashCode() : 0;
|
||||
}
|
||||
|
||||
public static String typeToString(Type type) {
|
||||
return type instanceof Class ? ((Class<?>) type).getName() : type.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generic supertype for {@code supertype}. For example, given a class {@code
|
||||
* IntegerSet}, the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the
|
||||
* result when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
|
||||
*/
|
||||
static Type getGenericSupertype(Type context, Class<?> rawType, Class<?> toResolve) {
|
||||
if (toResolve == rawType) {
|
||||
return context;
|
||||
}
|
||||
|
||||
// we skip searching through interfaces if unknown is an interface
|
||||
if (toResolve.isInterface()) {
|
||||
Class<?>[] interfaces = rawType.getInterfaces();
|
||||
for (int i = 0, length = interfaces.length; i < length; i++) {
|
||||
if (interfaces[i] == toResolve) {
|
||||
return rawType.getGenericInterfaces()[i];
|
||||
} else if (toResolve.isAssignableFrom(interfaces[i])) {
|
||||
return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check our supertypes
|
||||
if (!rawType.isInterface()) {
|
||||
while (rawType != Object.class) {
|
||||
Class<?> rawSupertype = rawType.getSuperclass();
|
||||
if (rawSupertype == toResolve) {
|
||||
return rawType.getGenericSuperclass();
|
||||
} else if (toResolve.isAssignableFrom(rawSupertype)) {
|
||||
return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
|
||||
}
|
||||
rawType = rawSupertype;
|
||||
}
|
||||
}
|
||||
|
||||
// we can't resolve this further
|
||||
return toResolve;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the generic form of {@code supertype}. For example, if this is {@code
|
||||
* ArrayList<String>}, this returns {@code Iterable<String>} given the input {@code
|
||||
* Iterable.class}.
|
||||
*
|
||||
* @param supertype a superclass of, or interface implemented by, this.
|
||||
*/
|
||||
static Type getSupertype(Type context, Class<?> contextRawType, Class<?> supertype) {
|
||||
checkArgument(supertype.isAssignableFrom(contextRawType));
|
||||
return resolve(context, contextRawType,
|
||||
$Gson$Types.getGenericSupertype(context, contextRawType, supertype));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this type is an array.
|
||||
*/
|
||||
public static boolean isArray(Type type) {
|
||||
return type instanceof GenericArrayType
|
||||
|| (type instanceof Class && ((Class<?>) type).isArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component type of this array type.
|
||||
* @throws ClassCastException if this type is not an array.
|
||||
*/
|
||||
public static Type getArrayComponentType(Type array) {
|
||||
return array instanceof GenericArrayType
|
||||
? ((GenericArrayType) array).getGenericComponentType()
|
||||
: ((Class<?>) array).getComponentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element type of this collection type.
|
||||
* @throws IllegalArgumentException if this type is not a collection.
|
||||
*/
|
||||
public static Type getCollectionElementType(Type context, Class<?> contextRawType) {
|
||||
Type collectionType = getSupertype(context, contextRawType, Collection.class);
|
||||
|
||||
if (collectionType instanceof WildcardType) {
|
||||
collectionType = ((WildcardType)collectionType).getUpperBounds()[0];
|
||||
}
|
||||
if (collectionType instanceof ParameterizedType) {
|
||||
return ((ParameterizedType) collectionType).getActualTypeArguments()[0];
|
||||
}
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a two element array containing this map's key and value types in
|
||||
* positions 0 and 1 respectively.
|
||||
*/
|
||||
public static Type[] getMapKeyAndValueTypes(Type context, Class<?> contextRawType) {
|
||||
/*
|
||||
* Work around a problem with the declaration of java.util.Properties. That
|
||||
* class should extend Hashtable<String, String>, but it's declared to
|
||||
* extend Hashtable<Object, Object>.
|
||||
*/
|
||||
if (context == Properties.class) {
|
||||
return new Type[] { String.class, String.class }; // TODO: test subclasses of Properties!
|
||||
}
|
||||
|
||||
Type mapType = getSupertype(context, contextRawType, Map.class);
|
||||
// TODO: strip wildcards?
|
||||
if (mapType instanceof ParameterizedType) {
|
||||
ParameterizedType mapParameterizedType = (ParameterizedType) mapType;
|
||||
return mapParameterizedType.getActualTypeArguments();
|
||||
}
|
||||
return new Type[] { Object.class, Object.class };
|
||||
}
|
||||
|
||||
public static Type resolve(Type context, Class<?> contextRawType, Type toResolve) {
|
||||
// this implementation is made a little more complicated in an attempt to avoid object-creation
|
||||
while (true) {
|
||||
if (toResolve instanceof TypeVariable) {
|
||||
TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve;
|
||||
toResolve = resolveTypeVariable(context, contextRawType, typeVariable);
|
||||
if (toResolve == typeVariable) {
|
||||
return toResolve;
|
||||
}
|
||||
|
||||
} else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) {
|
||||
Class<?> original = (Class<?>) toResolve;
|
||||
Type componentType = original.getComponentType();
|
||||
Type newComponentType = resolve(context, contextRawType, componentType);
|
||||
return componentType == newComponentType
|
||||
? original
|
||||
: arrayOf(newComponentType);
|
||||
|
||||
} else if (toResolve instanceof GenericArrayType) {
|
||||
GenericArrayType original = (GenericArrayType) toResolve;
|
||||
Type componentType = original.getGenericComponentType();
|
||||
Type newComponentType = resolve(context, contextRawType, componentType);
|
||||
return componentType == newComponentType
|
||||
? original
|
||||
: arrayOf(newComponentType);
|
||||
|
||||
} else if (toResolve instanceof ParameterizedType) {
|
||||
ParameterizedType original = (ParameterizedType) toResolve;
|
||||
Type ownerType = original.getOwnerType();
|
||||
Type newOwnerType = resolve(context, contextRawType, ownerType);
|
||||
boolean changed = newOwnerType != ownerType;
|
||||
|
||||
Type[] args = original.getActualTypeArguments();
|
||||
for (int t = 0, length = args.length; t < length; t++) {
|
||||
Type resolvedTypeArgument = resolve(context, contextRawType, args[t]);
|
||||
if (resolvedTypeArgument != args[t]) {
|
||||
if (!changed) {
|
||||
args = args.clone();
|
||||
changed = true;
|
||||
}
|
||||
args[t] = resolvedTypeArgument;
|
||||
}
|
||||
}
|
||||
|
||||
return changed
|
||||
? newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args)
|
||||
: original;
|
||||
|
||||
} else if (toResolve instanceof WildcardType) {
|
||||
WildcardType original = (WildcardType) toResolve;
|
||||
Type[] originalLowerBound = original.getLowerBounds();
|
||||
Type[] originalUpperBound = original.getUpperBounds();
|
||||
|
||||
if (originalLowerBound.length == 1) {
|
||||
Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]);
|
||||
if (lowerBound != originalLowerBound[0]) {
|
||||
return supertypeOf(lowerBound);
|
||||
}
|
||||
} else if (originalUpperBound.length == 1) {
|
||||
Type upperBound = resolve(context, contextRawType, originalUpperBound[0]);
|
||||
if (upperBound != originalUpperBound[0]) {
|
||||
return subtypeOf(upperBound);
|
||||
}
|
||||
}
|
||||
return original;
|
||||
|
||||
} else {
|
||||
return toResolve;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Type resolveTypeVariable(Type context, Class<?> contextRawType, TypeVariable<?> unknown) {
|
||||
Class<?> declaredByRaw = declaringClassOf(unknown);
|
||||
|
||||
// we can't reduce this further
|
||||
if (declaredByRaw == null) {
|
||||
return unknown;
|
||||
}
|
||||
|
||||
Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw);
|
||||
if (declaredBy instanceof ParameterizedType) {
|
||||
int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
|
||||
return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
|
||||
}
|
||||
|
||||
return unknown;
|
||||
}
|
||||
|
||||
private static int indexOf(Object[] array, Object toFind) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (toFind.equals(array[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by
|
||||
* a class.
|
||||
*/
|
||||
private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) {
|
||||
GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
|
||||
return genericDeclaration instanceof Class
|
||||
? (Class<?>) genericDeclaration
|
||||
: null;
|
||||
}
|
||||
|
||||
private static void checkNotPrimitive(Type type) {
|
||||
checkArgument(!(type instanceof Class<?>) || !((Class<?>) type).isPrimitive());
|
||||
}
|
||||
|
||||
private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable {
|
||||
private final Type ownerType;
|
||||
private final Type rawType;
|
||||
private final Type[] typeArguments;
|
||||
|
||||
public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
|
||||
// require an owner type if the raw type needs it
|
||||
if (rawType instanceof Class<?>) {
|
||||
Class<?> rawTypeAsClass = (Class<?>) rawType;
|
||||
checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null);
|
||||
checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null);
|
||||
}
|
||||
|
||||
this.ownerType = ownerType == null ? null : canonicalize(ownerType);
|
||||
this.rawType = canonicalize(rawType);
|
||||
this.typeArguments = typeArguments.clone();
|
||||
for (int t = 0; t < this.typeArguments.length; t++) {
|
||||
checkNotNull(this.typeArguments[t]);
|
||||
checkNotPrimitive(this.typeArguments[t]);
|
||||
this.typeArguments[t] = canonicalize(this.typeArguments[t]);
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] getActualTypeArguments() {
|
||||
return typeArguments.clone();
|
||||
}
|
||||
|
||||
public Type getRawType() {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
public Type getOwnerType() {
|
||||
return ownerType;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object other) {
|
||||
return other instanceof ParameterizedType
|
||||
&& $Gson$Types.equals(this, (ParameterizedType) other);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return Arrays.hashCode(typeArguments)
|
||||
^ rawType.hashCode()
|
||||
^ hashCodeOrZero(ownerType);
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
|
||||
stringBuilder.append(typeToString(rawType));
|
||||
|
||||
if (typeArguments.length == 0) {
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
stringBuilder.append("<").append(typeToString(typeArguments[0]));
|
||||
for (int i = 1; i < typeArguments.length; i++) {
|
||||
stringBuilder.append(", ").append(typeToString(typeArguments[i]));
|
||||
}
|
||||
return stringBuilder.append(">").toString();
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
private static final class GenericArrayTypeImpl implements GenericArrayType, Serializable {
|
||||
private final Type componentType;
|
||||
|
||||
public GenericArrayTypeImpl(Type componentType) {
|
||||
this.componentType = canonicalize(componentType);
|
||||
}
|
||||
|
||||
public Type getGenericComponentType() {
|
||||
return componentType;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
return o instanceof GenericArrayType
|
||||
&& $Gson$Types.equals(this, (GenericArrayType) o);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
return componentType.hashCode();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return typeToString(componentType) + "[]";
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The WildcardType interface supports multiple upper bounds and multiple
|
||||
* lower bounds. We only support what the Java 6 language needs - at most one
|
||||
* bound. If a lower bound is set, the upper bound must be Object.class.
|
||||
*/
|
||||
private static final class WildcardTypeImpl implements WildcardType, Serializable {
|
||||
private final Type upperBound;
|
||||
private final Type lowerBound;
|
||||
|
||||
public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
|
||||
checkArgument(lowerBounds.length <= 1);
|
||||
checkArgument(upperBounds.length == 1);
|
||||
|
||||
if (lowerBounds.length == 1) {
|
||||
checkNotNull(lowerBounds[0]);
|
||||
checkNotPrimitive(lowerBounds[0]);
|
||||
checkArgument(upperBounds[0] == Object.class);
|
||||
this.lowerBound = canonicalize(lowerBounds[0]);
|
||||
this.upperBound = Object.class;
|
||||
|
||||
} else {
|
||||
checkNotNull(upperBounds[0]);
|
||||
checkNotPrimitive(upperBounds[0]);
|
||||
this.lowerBound = null;
|
||||
this.upperBound = canonicalize(upperBounds[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] getUpperBounds() {
|
||||
return new Type[] { upperBound };
|
||||
}
|
||||
|
||||
public Type[] getLowerBounds() {
|
||||
return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object other) {
|
||||
return other instanceof WildcardType
|
||||
&& $Gson$Types.equals(this, (WildcardType) other);
|
||||
}
|
||||
|
||||
@Override public int hashCode() {
|
||||
// this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
|
||||
return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
|
||||
^ (31 + upperBound.hashCode());
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
if (lowerBound != null) {
|
||||
return "? super " + typeToString(lowerBound);
|
||||
} else if (upperBound == Object.class) {
|
||||
return "?";
|
||||
} else {
|
||||
return "? extends " + typeToString(upperBound);
|
||||
}
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.InstanceCreator;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Returns a function that can construct an instance of a requested type.
|
||||
*/
|
||||
public final class ConstructorConstructor {
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators;
|
||||
|
||||
public ConstructorConstructor(ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) {
|
||||
this.instanceCreators = instanceCreators;
|
||||
}
|
||||
|
||||
public ConstructorConstructor() {
|
||||
this(new ParameterizedTypeHandlerMap<InstanceCreator<?>>());
|
||||
}
|
||||
|
||||
public <T> ObjectConstructor<T> getConstructor(TypeToken<T> typeToken) {
|
||||
final Type type = typeToken.getType();
|
||||
final Class<? super T> rawType = typeToken.getRawType();
|
||||
|
||||
// first try an instance creator
|
||||
|
||||
@SuppressWarnings("unchecked") // types must agree
|
||||
final InstanceCreator<T> creator
|
||||
= (InstanceCreator<T>) instanceCreators.getHandlerFor(type, false);
|
||||
if (creator != null) {
|
||||
return new ObjectConstructor<T>() {
|
||||
public T construct() {
|
||||
return creator.createInstance(type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
|
||||
if (defaultConstructor != null) {
|
||||
return defaultConstructor;
|
||||
}
|
||||
|
||||
ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(rawType);
|
||||
if (defaultImplementation != null) {
|
||||
return defaultImplementation;
|
||||
}
|
||||
|
||||
// finally try unsafe
|
||||
return newUnsafeAllocator(type, rawType);
|
||||
}
|
||||
|
||||
private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
|
||||
try {
|
||||
final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
|
||||
if (!constructor.isAccessible()) {
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
return new ObjectConstructor<T>() {
|
||||
@SuppressWarnings("unchecked") // T is the same raw type as is requested
|
||||
public T construct() {
|
||||
try {
|
||||
Object[] args = null;
|
||||
return (T) constructor.newInstance(args);
|
||||
} catch (InstantiationException e) {
|
||||
// TODO: JsonParseException ?
|
||||
throw new RuntimeException("Failed to invoke " + constructor + " with no args", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
// TODO: don't wrap if cause is unchecked!
|
||||
// TODO: JsonParseException ?
|
||||
throw new RuntimeException("Failed to invoke " + constructor + " with no args",
|
||||
e.getTargetException());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructors for common interface types like Map and List and their
|
||||
* subytpes.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is
|
||||
private <T> ObjectConstructor<T> newDefaultImplementationConstructor(Class<? super T> rawType) {
|
||||
if (Collection.class.isAssignableFrom(rawType)) {
|
||||
if (SortedSet.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
public T construct() {
|
||||
return (T) new TreeSet<Object>();
|
||||
}
|
||||
};
|
||||
} else if (Set.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
public T construct() {
|
||||
return (T) new LinkedHashSet<Object>();
|
||||
}
|
||||
};
|
||||
} else if (Queue.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
public T construct() {
|
||||
return (T) new LinkedList<Object>();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return new ObjectConstructor<T>() {
|
||||
public T construct() {
|
||||
return (T) new ArrayList<Object>();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (Map.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
public T construct() {
|
||||
return (T) new LinkedHashMap<Object, Object>();
|
||||
}
|
||||
};
|
||||
// TODO: SortedMap ?
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T> ObjectConstructor<T> newUnsafeAllocator(
|
||||
final Type type, final Class<? super T> rawType) {
|
||||
return new ObjectConstructor<T>() {
|
||||
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
|
||||
@SuppressWarnings("unchecked")
|
||||
public T construct() {
|
||||
try {
|
||||
Object newInstance = unsafeAllocator.newInstance(rawType);
|
||||
return (T) newInstance;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
|
||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return instanceCreators.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* This class holds a number value that is lazily converted to a specific number type
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public final class LazilyParsedNumber extends Number {
|
||||
private final String value;
|
||||
|
||||
public LazilyParsedNumber(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int intValue() {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
try {
|
||||
return (int) Long.parseLong(value);
|
||||
} catch (NumberFormatException nfe) {
|
||||
return new BigInteger(value).intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long longValue() {
|
||||
try {
|
||||
return Long.parseLong(value);
|
||||
} catch (NumberFormatException e) {
|
||||
return new BigInteger(value).longValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float floatValue() {
|
||||
return Float.parseFloat(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double doubleValue() {
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public interface ObjectConstructor<T> {
|
||||
|
||||
/**
|
||||
* Returns a new instance.
|
||||
*/
|
||||
public T construct();
|
||||
}
|
||||
61
src/com/massivecraft/mcore2/lib/gson/internal/Pair.java
Normal file
61
src/com/massivecraft/mcore2/lib/gson/internal/Pair.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
/**
|
||||
* A simple object that holds onto a pair of object references, first and second.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @param <FIRST>
|
||||
* @param <SECOND>
|
||||
*/
|
||||
public final class Pair<FIRST, SECOND> {
|
||||
public final FIRST first;
|
||||
public final SECOND second;
|
||||
|
||||
public 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
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
|
||||
*/
|
||||
public final class ParameterizedTypeHandlerMap<T> {
|
||||
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ParameterizedTypeHandlerMap.class.getName());
|
||||
/**
|
||||
* Map that is meant for storing default type adapters
|
||||
*/
|
||||
private final Map<Type, T> systemMap = new HashMap<Type, T>();
|
||||
private final Map<Type, T> userMap = new HashMap<Type, T>();
|
||||
/**
|
||||
* List of default type hierarchy adapters
|
||||
*/
|
||||
private final List<Pair<Class<?>, T>> systemTypeHierarchyList = new ArrayList<Pair<Class<?>, T>>();
|
||||
private final List<Pair<Class<?>, T>> userTypeHierarchyList = new ArrayList<Pair<Class<?>, T>>();
|
||||
private boolean modifiable = true;
|
||||
|
||||
public synchronized void registerForTypeHierarchy(Class<?> typeOfT, T value, boolean isSystem) {
|
||||
Pair<Class<?>, T> pair = new Pair<Class<?>, T>(typeOfT, value);
|
||||
registerForTypeHierarchy(pair, isSystem);
|
||||
}
|
||||
|
||||
public synchronized void registerForTypeHierarchy(Pair<Class<?>, T> pair, boolean isSystem) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
List<Pair<Class<?>, T>> typeHierarchyList = isSystem ? systemTypeHierarchyList : userTypeHierarchyList;
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(pair.first, typeHierarchyList);
|
||||
if (index >= 0) {
|
||||
logger.log(Level.WARNING, "Overriding the existing type handler for {0}", pair.first);
|
||||
typeHierarchyList.remove(index);
|
||||
}
|
||||
index = getIndexOfAnOverriddenHandler(pair.first, typeHierarchyList);
|
||||
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 static <T> int getIndexOfAnOverriddenHandler(Class<?> type, List<Pair<Class<?>, T>> typeHierarchyList) {
|
||||
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, boolean isSystem) {
|
||||
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<Type, T> map = isSystem ? systemMap : userMap;
|
||||
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.userMap.entrySet()) {
|
||||
if (!userMap.containsKey(entry.getKey())) {
|
||||
register(entry.getKey(), entry.getValue(), false);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Type, T> entry : other.systemMap.entrySet()) {
|
||||
if (!systemMap.containsKey(entry.getKey())) {
|
||||
register(entry.getKey(), entry.getValue(), true);
|
||||
}
|
||||
}
|
||||
// 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.userTypeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = other.userTypeHierarchyList.get(i);
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first, userTypeHierarchyList);
|
||||
if (index < 0) {
|
||||
registerForTypeHierarchy(entry, false);
|
||||
}
|
||||
}
|
||||
for (int i = other.systemTypeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = other.systemTypeHierarchyList.get(i);
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first, systemTypeHierarchyList);
|
||||
if (index < 0) {
|
||||
registerForTypeHierarchy(entry, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ParameterizedTypeHandlerMap<T> makeUnmodifiable() {
|
||||
modifiable = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized T getHandlerFor(Type type, boolean systemOnly) {
|
||||
T handler;
|
||||
if (!systemOnly) {
|
||||
handler = userMap.get(type);
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
handler = systemMap.get(type);
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
}
|
||||
Class<?> rawClass = $Gson$Types.getRawType(type);
|
||||
if (rawClass != type) {
|
||||
handler = getHandlerFor(rawClass, systemOnly);
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
// check if something registered for type hierarchy
|
||||
handler = getHandlerForTypeHierarchy(rawClass, systemOnly);
|
||||
return handler;
|
||||
}
|
||||
|
||||
private T getHandlerForTypeHierarchy(Class<?> type, boolean systemOnly) {
|
||||
if (!systemOnly) {
|
||||
for (Pair<Class<?>, T> entry : userTypeHierarchyList) {
|
||||
if (entry.first.isAssignableFrom(type)) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Pair<Class<?>, T> entry : systemTypeHierarchyList) {
|
||||
if (entry.first.isAssignableFrom(type)) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized boolean hasSpecificHandlerFor(Type type) {
|
||||
return userMap.containsKey(type) || systemMap.containsKey(type);
|
||||
}
|
||||
|
||||
private static <T> int getIndexOfSpecificHandlerForTypeHierarchy(
|
||||
Class<?> type, List<Pair<Class<?>, T>> typeHierarchyList) {
|
||||
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>();
|
||||
// Instead of individually registering entries in the map, make an efficient copy
|
||||
// of the list and map
|
||||
|
||||
// TODO (inder): Performance optimization. We can probably just share the
|
||||
// systemMap and systemTypeHierarchyList instead of making copies
|
||||
copy.systemMap.putAll(systemMap);
|
||||
copy.userMap.putAll(userMap);
|
||||
copy.systemTypeHierarchyList.addAll(systemTypeHierarchyList);
|
||||
copy.userTypeHierarchyList.addAll(userTypeHierarchyList);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{userTypeHierarchyList:{");
|
||||
appendList(sb, userTypeHierarchyList);
|
||||
sb.append("},systemTypeHierarchyList:{");
|
||||
appendList(sb, systemTypeHierarchyList);
|
||||
sb.append("},userMap:{");
|
||||
appendMap(sb, userMap);
|
||||
sb.append("},systemMap:{");
|
||||
appendMap(sb, systemMap);
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendList(StringBuilder sb, List<Pair<Class<?>,T>> list) {
|
||||
boolean first = true;
|
||||
for (Pair<Class<?>, T> entry : list) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(typeToString(entry.first)).append(':');
|
||||
sb.append(entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendMap(StringBuilder sb, Map<Type, T> map) {
|
||||
boolean 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());
|
||||
}
|
||||
}
|
||||
|
||||
private String typeToString(Type type) {
|
||||
return $Gson$Types.getRawType(type).getSimpleName();
|
||||
}
|
||||
}
|
||||
119
src/com/massivecraft/mcore2/lib/gson/internal/Primitives.java
Normal file
119
src/com/massivecraft/mcore2/lib/gson/internal/Primitives.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Contains static utility methods pertaining to primitive types and their
|
||||
* corresponding wrapper types.
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
public final class Primitives {
|
||||
private Primitives() {}
|
||||
|
||||
/** A map from primitive types to their corresponding wrapper types. */
|
||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE;
|
||||
|
||||
/** A map from wrapper types to their corresponding primitive types. */
|
||||
private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE;
|
||||
|
||||
// Sad that we can't use a BiMap. :(
|
||||
|
||||
static {
|
||||
Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16);
|
||||
Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16);
|
||||
|
||||
add(primToWrap, wrapToPrim, boolean.class, Boolean.class);
|
||||
add(primToWrap, wrapToPrim, byte.class, Byte.class);
|
||||
add(primToWrap, wrapToPrim, char.class, Character.class);
|
||||
add(primToWrap, wrapToPrim, double.class, Double.class);
|
||||
add(primToWrap, wrapToPrim, float.class, Float.class);
|
||||
add(primToWrap, wrapToPrim, int.class, Integer.class);
|
||||
add(primToWrap, wrapToPrim, long.class, Long.class);
|
||||
add(primToWrap, wrapToPrim, short.class, Short.class);
|
||||
add(primToWrap, wrapToPrim, void.class, Void.class);
|
||||
|
||||
PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap);
|
||||
WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim);
|
||||
}
|
||||
|
||||
private static void add(Map<Class<?>, Class<?>> forward,
|
||||
Map<Class<?>, Class<?>> backward, Class<?> key, Class<?> value) {
|
||||
forward.put(key, value);
|
||||
backward.put(value, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this type is a primitive.
|
||||
*/
|
||||
public static boolean isPrimitive(Type type) {
|
||||
return PRIMITIVE_TO_WRAPPER_TYPE.containsKey(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if {@code type} is one of the nine
|
||||
* primitive-wrapper types, such as {@link Integer}.
|
||||
*
|
||||
* @see Class#isPrimitive
|
||||
*/
|
||||
public static boolean isWrapperType(Type type) {
|
||||
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(
|
||||
$Gson$Preconditions.checkNotNull(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding wrapper type of {@code type} if it is a primitive
|
||||
* type; otherwise returns {@code type} itself. Idempotent.
|
||||
* <pre>
|
||||
* wrap(int.class) == Integer.class
|
||||
* wrap(Integer.class) == Integer.class
|
||||
* wrap(String.class) == String.class
|
||||
* </pre>
|
||||
*/
|
||||
public static <T> Class<T> wrap(Class<T> type) {
|
||||
// cast is safe: long.class and Long.class are both of type Class<Long>
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<T> wrapped = (Class<T>) PRIMITIVE_TO_WRAPPER_TYPE.get(
|
||||
$Gson$Preconditions.checkNotNull(type));
|
||||
return (wrapped == null) ? type : wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding primitive type of {@code type} if it is a
|
||||
* wrapper type; otherwise returns {@code type} itself. Idempotent.
|
||||
* <pre>
|
||||
* unwrap(Integer.class) == int.class
|
||||
* unwrap(int.class) == int.class
|
||||
* unwrap(String.class) == String.class
|
||||
* </pre>
|
||||
*/
|
||||
public static <T> Class<T> unwrap(Class<T> type) {
|
||||
// cast is safe: long.class and Long.class are both of type Class<Long>
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get(
|
||||
$Gson$Preconditions.checkNotNull(type));
|
||||
return (unwrapped == null) ? type : unwrapped;
|
||||
}
|
||||
}
|
||||
116
src/com/massivecraft/mcore2/lib/gson/internal/Streams.java
Normal file
116
src/com/massivecraft/mcore2/lib/gson/internal/Streams.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapters;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.MalformedJsonException;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Reads and writes GSON parse trees over streams.
|
||||
*/
|
||||
public final class Streams {
|
||||
/**
|
||||
* Takes a reader in any state and returns the next value as a JsonElement.
|
||||
*/
|
||||
public static JsonElement parse(JsonReader reader) throws JsonParseException {
|
||||
boolean isEmpty = true;
|
||||
try {
|
||||
reader.peek();
|
||||
isEmpty = false;
|
||||
return TypeAdapters.JSON_ELEMENT.read(reader);
|
||||
} catch (EOFException e) {
|
||||
/*
|
||||
* For compatibility with JSON 1.5 and earlier, we return a JsonNull for
|
||||
* empty documents instead of throwing.
|
||||
*/
|
||||
if (isEmpty) {
|
||||
return JsonNull.INSTANCE;
|
||||
}
|
||||
throw new JsonIOException(e);
|
||||
} catch (MalformedJsonException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the JSON element to the writer, recursively.
|
||||
*/
|
||||
public static void write(JsonElement element, JsonWriter writer) throws IOException {
|
||||
TypeAdapters.JSON_ELEMENT.write(writer, element);
|
||||
}
|
||||
|
||||
public static Writer writerForAppendable(Appendable appendable) {
|
||||
return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer}
|
||||
* is used.
|
||||
*/
|
||||
private static class AppendableWriter extends Writer {
|
||||
private final Appendable appendable;
|
||||
private final CurrentWrite currentWrite = new CurrentWrite();
|
||||
|
||||
private AppendableWriter(Appendable appendable) {
|
||||
this.appendable = appendable;
|
||||
}
|
||||
|
||||
@Override public void write(char[] chars, int offset, int length) throws IOException {
|
||||
currentWrite.chars = chars;
|
||||
appendable.append(currentWrite, offset, offset + length);
|
||||
}
|
||||
|
||||
@Override public void write(int i) throws IOException {
|
||||
appendable.append((char) i);
|
||||
}
|
||||
|
||||
@Override public void flush() {}
|
||||
@Override public void close() {}
|
||||
|
||||
/**
|
||||
* A mutable char sequence pointing at a single char[].
|
||||
*/
|
||||
static class CurrentWrite implements CharSequence {
|
||||
char[] chars;
|
||||
public int length() {
|
||||
return chars.length;
|
||||
}
|
||||
public char charAt(int i) {
|
||||
return chars[i];
|
||||
}
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return new String(chars, start, end - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Do sneaky things to allocate objects without invoking their constructors.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public abstract class UnsafeAllocator {
|
||||
public abstract <T> T newInstance(Class<T> c) throws Exception;
|
||||
|
||||
public static UnsafeAllocator create() {
|
||||
// try JVM
|
||||
// public class Unsafe {
|
||||
// public Object allocateInstance(Class<?> type);
|
||||
// }
|
||||
try {
|
||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
Field f = unsafeClass.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
final Object unsafe = f.get(null);
|
||||
final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
|
||||
return new UnsafeAllocator() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T newInstance(Class<T> c) throws Exception {
|
||||
return (T) allocateInstance.invoke(unsafe, c);
|
||||
}
|
||||
};
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
// try dalvikvm, pre-gingerbread
|
||||
// public class ObjectInputStream {
|
||||
// private static native Object newInstance(
|
||||
// Class<?> instantiationClass, Class<?> constructorClass);
|
||||
// }
|
||||
try {
|
||||
final Method newInstance = ObjectInputStream.class
|
||||
.getDeclaredMethod("newInstance", Class.class, Class.class);
|
||||
newInstance.setAccessible(true);
|
||||
return new UnsafeAllocator() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T newInstance(Class<T> c) throws Exception {
|
||||
return (T) newInstance.invoke(null, c, Object.class);
|
||||
}
|
||||
};
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
// try dalvikvm, post-gingerbread
|
||||
// public class ObjectStreamClass {
|
||||
// private static native int getConstructorId(Class<?> c);
|
||||
// private static native Object newInstance(Class<?> instantiationClass, int methodId);
|
||||
// }
|
||||
try {
|
||||
Method getConstructorId = ObjectStreamClass.class
|
||||
.getDeclaredMethod("getConstructorId", Class.class);
|
||||
getConstructorId.setAccessible(true);
|
||||
final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
|
||||
final Method newInstance = ObjectStreamClass.class
|
||||
.getDeclaredMethod("newInstance", Class.class, int.class);
|
||||
newInstance.setAccessible(true);
|
||||
return new UnsafeAllocator() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T newInstance(Class<T> c) throws Exception {
|
||||
return (T) newInstance.invoke(null, c, constructorId);
|
||||
}
|
||||
};
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
// give up
|
||||
return new UnsafeAllocator() {
|
||||
@Override
|
||||
public <T> T newInstance(Class<T> c) {
|
||||
throw new UnsupportedOperationException("Cannot allocate " + c);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Adapt an array of objects.
|
||||
*/
|
||||
public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
if (!(type instanceof GenericArrayType || type instanceof Class && ((Class<?>) type).isArray())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type componentType = $Gson$Types.getArrayComponentType(type);
|
||||
TypeAdapter<?> componentTypeAdapter = context.getAdapter(TypeToken.get(componentType));
|
||||
// create() doesn't define a type parameter
|
||||
TypeAdapter<T> result = new ArrayTypeAdapter(
|
||||
context, componentTypeAdapter, $Gson$Types.getRawType(componentType));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private final Class<E> componentType;
|
||||
private final TypeAdapter<E> componentTypeAdapter;
|
||||
|
||||
public ArrayTypeAdapter(MiniGson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) {
|
||||
this.componentTypeAdapter =
|
||||
new TypeAdapterRuntimeTypeWrapper<E>(context, componentTypeAdapter, componentType);
|
||||
this.componentType = componentType;
|
||||
}
|
||||
|
||||
public Object read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
List<E> list = new ArrayList<E>();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
E instance = componentTypeAdapter.read(reader);
|
||||
list.add(instance);
|
||||
}
|
||||
reader.endArray();
|
||||
Object array = Array.newInstance(componentType, list.size());
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Array.set(array, i, list.get(i));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override public void write(JsonWriter writer, Object array) throws IOException {
|
||||
if (array == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginArray();
|
||||
for (int i = 0, length = Array.getLength(array); i < length; i++) {
|
||||
final E value = (E) Array.get(array, i);
|
||||
componentTypeAdapter.write(writer, value);
|
||||
}
|
||||
writer.endArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Adapts a BigDecimal type to and from its JSON representation.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal> {
|
||||
|
||||
@Override
|
||||
public BigDecimal read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(reader.nextString());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, BigDecimal value) throws IOException {
|
||||
writer.value(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Adapts a BigInteger type to and from its JSON representation.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class BigIntegerTypeAdapter extends TypeAdapter<BigInteger> {
|
||||
|
||||
@Override
|
||||
public BigInteger read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigInteger(reader.nextString());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, BigInteger value) throws IOException {
|
||||
writer.value(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ObjectConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Adapt a homogeneous collection of objects.
|
||||
*/
|
||||
public final class CollectionTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Collection.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
|
||||
TypeAdapter<?> elementTypeAdapter = context.getAdapter(TypeToken.get(elementType));
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter
|
||||
TypeAdapter<T> result = new Adapter(context, elementType, elementTypeAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final class Adapter<E> extends TypeAdapter<Collection<E>> {
|
||||
private final TypeAdapter<E> elementTypeAdapter;
|
||||
private final ObjectConstructor<? extends Collection<E>> constructor;
|
||||
|
||||
public Adapter(MiniGson context, Type elementType,
|
||||
TypeAdapter<E> elementTypeAdapter,
|
||||
ObjectConstructor<? extends Collection<E>> constructor) {
|
||||
this.elementTypeAdapter =
|
||||
new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Collection<E> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<E> collection = constructor.construct();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
E instance = elementTypeAdapter.read(reader);
|
||||
collection.add(instance);
|
||||
}
|
||||
reader.endArray();
|
||||
return collection;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Collection<E> collection) throws IOException {
|
||||
if (collection == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginArray();
|
||||
for (E element : collection) {
|
||||
elementTypeAdapter.write(writer, element);
|
||||
}
|
||||
writer.endArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Adapter for Date. Although this class appears stateless, it is not.
|
||||
* DateFormat captures its time zone and locale when it is created, which gives
|
||||
* this class state. DateFormat isn't thread safe either, so this class has
|
||||
* to synchronize its read and write methods.
|
||||
*/
|
||||
public final class DateTypeAdapter extends TypeAdapter<Date> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) new DateTypeAdapter() : null;
|
||||
}
|
||||
};
|
||||
|
||||
private final DateFormat enUsFormat
|
||||
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US);
|
||||
private final DateFormat localFormat
|
||||
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
|
||||
private final DateFormat iso8601Format = buildIso8601Format();
|
||||
|
||||
private static DateFormat buildIso8601Format() {
|
||||
DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return iso8601Format;
|
||||
}
|
||||
|
||||
@Override public Date read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return deserializeToDate(reader.nextString());
|
||||
}
|
||||
|
||||
private synchronized Date deserializeToDate(String json) {
|
||||
try {
|
||||
return localFormat.parse(json);
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
try {
|
||||
return enUsFormat.parse(json);
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
try {
|
||||
return iso8601Format.parse(json);
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(json, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void write(JsonWriter writer, Date value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
String dateFormatAsString = enUsFormat.format(value);
|
||||
writer.value(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.ExclusionStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This type adapter skips values using an exclusion strategy. It may delegate
|
||||
* to another type adapter if only one direction is excluded.
|
||||
*/
|
||||
public final class ExcludedTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ExclusionStrategy serializationExclusionStrategy;
|
||||
private final ExclusionStrategy deserializationExclusionStrategy;
|
||||
|
||||
public ExcludedTypeAdapterFactory(ExclusionStrategy serializationExclusionStrategy,
|
||||
ExclusionStrategy deserializationExclusionStrategy) {
|
||||
this.serializationExclusionStrategy = serializationExclusionStrategy;
|
||||
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final MiniGson context, final TypeToken<T> type) {
|
||||
Class<?> rawType = type.getRawType();
|
||||
final boolean skipSerialize = serializationExclusionStrategy.shouldSkipClass(rawType);
|
||||
final boolean skipDeserialize = deserializationExclusionStrategy.shouldSkipClass(rawType);
|
||||
|
||||
if (!skipSerialize && !skipDeserialize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
/**
|
||||
* The delegate is lazily created because it may not be needed, and
|
||||
* creating it may fail.
|
||||
*/
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (skipDeserialize) {
|
||||
reader.skipValue();
|
||||
return null;
|
||||
}
|
||||
return delegate().read(reader);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (skipSerialize) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
delegate().write(writer, value);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = context.getNextAdapter(ExcludedTypeAdapterFactory.this, type));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This reader walks the elements of a JsonElement as if it was coming from a
|
||||
* character stream.
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public final class JsonElementReader extends JsonReader {
|
||||
private static final Reader UNREADABLE_READER = new Reader() {
|
||||
@Override public int read(char[] buffer, int offset, int count) throws IOException {
|
||||
throw new AssertionError();
|
||||
}
|
||||
@Override public void close() throws IOException {
|
||||
throw new AssertionError();
|
||||
}
|
||||
};
|
||||
private static final Object SENTINEL_CLOSED = new Object();
|
||||
|
||||
private final List<Object> stack = new ArrayList<Object>();
|
||||
|
||||
public JsonElementReader(JsonElement element) {
|
||||
super(UNREADABLE_READER);
|
||||
stack.add(element);
|
||||
}
|
||||
|
||||
@Override public void beginArray() throws IOException {
|
||||
expect(JsonToken.BEGIN_ARRAY);
|
||||
JsonArray array = (JsonArray) peekStack();
|
||||
stack.add(array.iterator());
|
||||
}
|
||||
|
||||
@Override public void endArray() throws IOException {
|
||||
expect(JsonToken.END_ARRAY);
|
||||
popStack(); // empty iterator
|
||||
popStack(); // array
|
||||
}
|
||||
|
||||
@Override public void beginObject() throws IOException {
|
||||
expect(JsonToken.BEGIN_OBJECT);
|
||||
JsonObject object = (JsonObject) peekStack();
|
||||
stack.add(object.entrySet().iterator());
|
||||
}
|
||||
|
||||
@Override public void endObject() throws IOException {
|
||||
expect(JsonToken.END_OBJECT);
|
||||
popStack(); // empty iterator
|
||||
popStack(); // object
|
||||
}
|
||||
|
||||
@Override public boolean hasNext() throws IOException {
|
||||
JsonToken token = peek();
|
||||
return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
|
||||
}
|
||||
|
||||
@Override public JsonToken peek() throws IOException {
|
||||
if (stack.isEmpty()) {
|
||||
return JsonToken.END_DOCUMENT;
|
||||
}
|
||||
|
||||
Object o = peekStack();
|
||||
if (o instanceof Iterator) {
|
||||
boolean isObject = stack.get(stack.size() - 2) instanceof JsonObject;
|
||||
Iterator<?> iterator = (Iterator<?>) o;
|
||||
if (iterator.hasNext()) {
|
||||
if (isObject) {
|
||||
return JsonToken.NAME;
|
||||
} else {
|
||||
stack.add(iterator.next());
|
||||
return peek();
|
||||
}
|
||||
} else {
|
||||
return isObject ? JsonToken.END_OBJECT : JsonToken.END_ARRAY;
|
||||
}
|
||||
} else if (o instanceof JsonObject) {
|
||||
return JsonToken.BEGIN_OBJECT;
|
||||
} else if (o instanceof JsonArray) {
|
||||
return JsonToken.BEGIN_ARRAY;
|
||||
} else if (o instanceof JsonPrimitive) {
|
||||
JsonPrimitive primitive = (JsonPrimitive) o;
|
||||
if (primitive.isString()) {
|
||||
return JsonToken.STRING;
|
||||
} else if (primitive.isBoolean()) {
|
||||
return JsonToken.BOOLEAN;
|
||||
} else if (primitive.isNumber()) {
|
||||
return JsonToken.NUMBER;
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
} else if (o instanceof JsonNull) {
|
||||
return JsonToken.NULL;
|
||||
} else if (o == SENTINEL_CLOSED) {
|
||||
throw new IllegalStateException("JsonReader is closed");
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
private Object peekStack() {
|
||||
return stack.get(stack.size() - 1);
|
||||
}
|
||||
|
||||
private Object popStack() {
|
||||
return stack.remove(stack.size() - 1);
|
||||
}
|
||||
|
||||
private void expect(JsonToken expected) throws IOException {
|
||||
if (peek() != expected) {
|
||||
throw new IllegalStateException("Expected " + expected + " but was " + peek());
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String nextName() throws IOException {
|
||||
expect(JsonToken.NAME);
|
||||
Iterator<?> i = (Iterator<?>) peekStack();
|
||||
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();
|
||||
stack.add(entry.getValue());
|
||||
return (String) entry.getKey();
|
||||
}
|
||||
|
||||
@Override public String nextString() throws IOException {
|
||||
JsonToken token = peek();
|
||||
if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
|
||||
throw new IllegalStateException("Expected " + JsonToken.STRING + " but was " + token);
|
||||
}
|
||||
return ((JsonPrimitive) popStack()).getAsString();
|
||||
}
|
||||
|
||||
@Override public boolean nextBoolean() throws IOException {
|
||||
expect(JsonToken.BOOLEAN);
|
||||
return ((JsonPrimitive) popStack()).getAsBoolean();
|
||||
}
|
||||
|
||||
@Override public void nextNull() throws IOException {
|
||||
expect(JsonToken.NULL);
|
||||
popStack();
|
||||
}
|
||||
|
||||
@Override public double nextDouble() throws IOException {
|
||||
JsonToken token = peek();
|
||||
if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
|
||||
throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
|
||||
}
|
||||
double result = ((JsonPrimitive) peekStack()).getAsDouble();
|
||||
if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) {
|
||||
throw new NumberFormatException("JSON forbids NaN and infinities: " + result);
|
||||
}
|
||||
popStack();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public long nextLong() throws IOException {
|
||||
JsonToken token = peek();
|
||||
if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
|
||||
throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
|
||||
}
|
||||
long result = ((JsonPrimitive) peekStack()).getAsLong();
|
||||
popStack();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public int nextInt() throws IOException {
|
||||
JsonToken token = peek();
|
||||
if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
|
||||
throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
|
||||
}
|
||||
int result = ((JsonPrimitive) peekStack()).getAsInt();
|
||||
popStack();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public void close() throws IOException {
|
||||
stack.clear();
|
||||
stack.add(SENTINEL_CLOSED);
|
||||
}
|
||||
|
||||
@Override public void skipValue() throws IOException {
|
||||
if (peek() == JsonToken.NAME) {
|
||||
nextName();
|
||||
} else {
|
||||
popStack();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This writer creates a JsonElement.
|
||||
*/
|
||||
public final class JsonElementWriter extends JsonWriter {
|
||||
private static final Writer UNWRITABLE_WRITER = new Writer() {
|
||||
@Override public void write(char[] buffer, int offset, int counter) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
@Override public void flush() throws IOException {
|
||||
throw new AssertionError();
|
||||
}
|
||||
@Override public void close() throws IOException {
|
||||
throw new AssertionError();
|
||||
}
|
||||
};
|
||||
/** Added to the top of the stack when this writer is closed to cause following ops to fail. */
|
||||
private static final JsonPrimitive SENTINEL_CLOSED = new JsonPrimitive("closed");
|
||||
|
||||
/** The JsonElements and JsonArrays under modification, outermost to innermost. */
|
||||
private final List<JsonElement> stack = new ArrayList<JsonElement>();
|
||||
|
||||
/** The name for the next JSON object value. If non-null, the top of the stack is a JsonObject. */
|
||||
private String pendingName;
|
||||
|
||||
/** the JSON element constructed by this writer. */
|
||||
private JsonElement product = JsonNull.INSTANCE; // TODO: is this really what we want?;
|
||||
|
||||
public JsonElementWriter() {
|
||||
super(UNWRITABLE_WRITER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top level object produced by this writer.
|
||||
*/
|
||||
public JsonElement get() {
|
||||
if (!stack.isEmpty()) {
|
||||
throw new IllegalStateException("Expected one JSON element but was " + stack);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
private JsonElement peek() {
|
||||
return stack.get(stack.size() - 1);
|
||||
}
|
||||
|
||||
private void put(JsonElement value) {
|
||||
if (pendingName != null) {
|
||||
if (!value.isJsonNull() || getSerializeNulls()) {
|
||||
JsonObject object = (JsonObject) peek();
|
||||
object.add(pendingName, value);
|
||||
}
|
||||
pendingName = null;
|
||||
} else if (stack.isEmpty()) {
|
||||
product = value;
|
||||
} else {
|
||||
JsonElement element = peek();
|
||||
if (element instanceof JsonArray) {
|
||||
((JsonArray) element).add(value);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public JsonWriter beginArray() throws IOException {
|
||||
JsonArray array = new JsonArray();
|
||||
put(array);
|
||||
stack.add(array);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter endArray() throws IOException {
|
||||
if (stack.isEmpty() || pendingName != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
JsonElement element = peek();
|
||||
if (element instanceof JsonArray) {
|
||||
stack.remove(stack.size() - 1);
|
||||
return this;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override public JsonWriter beginObject() throws IOException {
|
||||
JsonObject object = new JsonObject();
|
||||
put(object);
|
||||
stack.add(object);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter endObject() throws IOException {
|
||||
if (stack.isEmpty() || pendingName != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
JsonElement element = peek();
|
||||
if (element instanceof JsonObject) {
|
||||
stack.remove(stack.size() - 1);
|
||||
return this;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override public JsonWriter name(String name) throws IOException {
|
||||
if (stack.isEmpty() || pendingName != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
JsonElement element = peek();
|
||||
if (element instanceof JsonObject) {
|
||||
pendingName = name;
|
||||
return this;
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(String value) throws IOException {
|
||||
if (value == null) {
|
||||
return nullValue();
|
||||
}
|
||||
put(new JsonPrimitive(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter nullValue() throws IOException {
|
||||
put(JsonNull.INSTANCE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(boolean value) throws IOException {
|
||||
put(new JsonPrimitive(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(double value) throws IOException {
|
||||
if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) {
|
||||
throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value);
|
||||
}
|
||||
put(new JsonPrimitive(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(long value) throws IOException {
|
||||
put(new JsonPrimitive(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(Number value) throws IOException {
|
||||
if (value == null) {
|
||||
return nullValue();
|
||||
}
|
||||
|
||||
if (!isLenient()) {
|
||||
double d = value.doubleValue();
|
||||
if (Double.isNaN(d) || Double.isInfinite(d)) {
|
||||
throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
put(new JsonPrimitive(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public void flush() throws IOException {
|
||||
}
|
||||
|
||||
@Override public void close() throws IOException {
|
||||
if (!stack.isEmpty()) {
|
||||
throw new IOException("Incomplete document");
|
||||
}
|
||||
stack.add(SENTINEL_CLOSED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ObjectConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapts maps to either JSON objects or JSON arrays.
|
||||
*
|
||||
* <h3>Maps as JSON objects</h3>
|
||||
* For primitive keys or when complex map key serialization is not enabled, this
|
||||
* 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.google.gson.JsonParseException: Expecting object found: "(5,6)"
|
||||
* at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
|
||||
* at com.google.gson.ObjectNavigator.navigateClassFields
|
||||
* ...</pre>
|
||||
*
|
||||
* <h3>Maps as JSON arrays</h3>
|
||||
* An alternative approach taken by this type adapter when it is required and
|
||||
* complex map key serialization is enabled 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.
|
||||
*/
|
||||
public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
private final boolean complexMapKeySerialization;
|
||||
|
||||
public MapTypeAdapterFactory(ConstructorConstructor constructorConstructor,
|
||||
boolean complexMapKeySerialization) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
this.complexMapKeySerialization = complexMapKeySerialization;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Map.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);
|
||||
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc);
|
||||
TypeAdapter<?> keyAdapter = getKeyAdapter(context, keyAndValueTypes[0]);
|
||||
TypeAdapter<?> valueAdapter = context.getAdapter(TypeToken.get(keyAndValueTypes[1]));
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
// we don't define a type parameter for the key or value types
|
||||
TypeAdapter<T> result = new Adapter(context, keyAndValueTypes[0], keyAdapter,
|
||||
keyAndValueTypes[1], valueAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type adapter that writes the value as a string.
|
||||
*/
|
||||
private TypeAdapter<?> getKeyAdapter(MiniGson context, Type keyType) {
|
||||
return (keyType == boolean.class || keyType == Boolean.class)
|
||||
? TypeAdapters.BOOLEAN_AS_STRING
|
||||
: context.getAdapter(TypeToken.get(keyType));
|
||||
}
|
||||
|
||||
private final class Adapter<K, V> extends TypeAdapter<Map<K, V>> {
|
||||
private final TypeAdapter<K> keyTypeAdapter;
|
||||
private final TypeAdapter<V> valueTypeAdapter;
|
||||
private final ObjectConstructor<? extends Map<K, V>> constructor;
|
||||
|
||||
public Adapter(MiniGson context, Type keyType, TypeAdapter<K> keyTypeAdapter,
|
||||
Type valueType, TypeAdapter<V> valueTypeAdapter,
|
||||
ObjectConstructor<? extends Map<K, V>> constructor) {
|
||||
this.keyTypeAdapter =
|
||||
new TypeAdapterRuntimeTypeWrapper<K>(context, keyTypeAdapter, keyType);
|
||||
this.valueTypeAdapter =
|
||||
new TypeAdapterRuntimeTypeWrapper<V>(context, valueTypeAdapter, valueType);
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Map<K, V> read(JsonReader reader) throws IOException {
|
||||
JsonToken peek = reader.peek();
|
||||
if (peek == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<K, V> map = constructor.construct();
|
||||
|
||||
if (peek == JsonToken.BEGIN_ARRAY) {
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
reader.beginArray(); // entry array
|
||||
K key = keyTypeAdapter.read(reader);
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
V replaced = map.put(key, value);
|
||||
if (replaced != null) {
|
||||
throw new JsonSyntaxException("duplicate key: " + key);
|
||||
}
|
||||
reader.endArray();
|
||||
}
|
||||
reader.endArray();
|
||||
} else {
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String keyString = reader.nextName();
|
||||
K key = keyTypeAdapter.fromJsonElement(new JsonPrimitive(keyString));
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
V replaced = map.put(key, value);
|
||||
if (replaced != null) {
|
||||
throw new JsonSyntaxException("duplicate key: " + key);
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Map<K, V> map) throws IOException {
|
||||
if (map == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
if (!complexMapKeySerialization) {
|
||||
writer.beginObject();
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
writer.name(String.valueOf(entry.getKey()));
|
||||
valueTypeAdapter.write(writer, entry.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasComplexKeys = false;
|
||||
List<JsonElement> keys = new ArrayList<JsonElement>(map.size());
|
||||
|
||||
List<V> values = new ArrayList<V>(map.size());
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
JsonElement keyElement = keyTypeAdapter.toJsonElement(entry.getKey());
|
||||
keys.add(keyElement);
|
||||
values.add(entry.getValue());
|
||||
hasComplexKeys |= keyElement.isJsonArray() || keyElement.isJsonObject();
|
||||
}
|
||||
|
||||
if (hasComplexKeys) {
|
||||
writer.beginArray();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
writer.beginArray(); // entry array
|
||||
Streams.write(keys.get(i), writer);
|
||||
valueTypeAdapter.write(writer, values.get(i));
|
||||
writer.endArray();
|
||||
}
|
||||
writer.endArray();
|
||||
} else {
|
||||
writer.beginObject();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
JsonElement keyElement = keys.get(i);
|
||||
writer.name(keyToString(keyElement));
|
||||
valueTypeAdapter.write(writer, values.get(i));
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
private String keyToString(JsonElement keyElement) {
|
||||
if (keyElement.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = keyElement.getAsJsonPrimitive();
|
||||
if (primitive.isNumber()) {
|
||||
return String.valueOf(primitive.getAsNumber());
|
||||
} else if (primitive.isBoolean()) {
|
||||
return Boolean.toString(primitive.getAsBoolean());
|
||||
} else if (primitive.isString()) {
|
||||
return primitive.getAsString();
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
} else if (keyElement.isJsonNull()) {
|
||||
return "null";
|
||||
} else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
207
src/com/massivecraft/mcore2/lib/gson/internal/bind/MiniGson.java
Normal file
207
src/com/massivecraft/mcore2/lib/gson/internal/bind/MiniGson.java
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A basic binding between JSON and Java objects.
|
||||
*/
|
||||
public final class MiniGson {
|
||||
/**
|
||||
* This thread local guards against reentrant calls to getAdapter(). In
|
||||
* certain object graphs, creating an adapter for a type may recursively
|
||||
* require an adapter for the same type! Without intervention, the recursive
|
||||
* lookup would stack overflow. We cheat by returning a proxy type adapter.
|
||||
* The proxy is wired up once the initial adapter has been created.
|
||||
*/
|
||||
private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls
|
||||
= new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>() {
|
||||
@Override protected Map<TypeToken<?>, FutureTypeAdapter<?>> initialValue() {
|
||||
return new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
|
||||
}
|
||||
};
|
||||
|
||||
private final List<TypeAdapter.Factory> factories;
|
||||
|
||||
private MiniGson(Builder builder) {
|
||||
ConstructorConstructor constructorConstructor = new ConstructorConstructor();
|
||||
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||
if (builder.addDefaultFactories) {
|
||||
factories.add(TypeAdapters.BOOLEAN_FACTORY);
|
||||
factories.add(TypeAdapters.INTEGER_FACTORY);
|
||||
factories.add(TypeAdapters.DOUBLE_FACTORY);
|
||||
factories.add(TypeAdapters.FLOAT_FACTORY);
|
||||
factories.add(TypeAdapters.LONG_FACTORY);
|
||||
factories.add(TypeAdapters.STRING_FACTORY);
|
||||
}
|
||||
factories.addAll(builder.factories);
|
||||
if (builder.addDefaultFactories) {
|
||||
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
|
||||
factories.add(new StringToValueMapTypeAdapterFactory(constructorConstructor));
|
||||
factories.add(ArrayTypeAdapter.FACTORY);
|
||||
factories.add(ObjectTypeAdapter.FACTORY);
|
||||
factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor));
|
||||
}
|
||||
this.factories = Collections.unmodifiableList(factories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type adapter for {@code} type.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
|
||||
// TODO: create a cache!
|
||||
|
||||
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
|
||||
@SuppressWarnings("unchecked") // the key and value type parameters always agree
|
||||
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
|
||||
if (ongoingCall != null) {
|
||||
return ongoingCall;
|
||||
}
|
||||
|
||||
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
|
||||
threadCalls.put(type, call);
|
||||
try {
|
||||
for (TypeAdapter.Factory factory : factories) {
|
||||
TypeAdapter<T> candidate = factory.create(this, type);
|
||||
if (candidate != null) {
|
||||
call.setDelegate(candidate);
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("This MiniGSON cannot handle " + type);
|
||||
} finally {
|
||||
threadCalls.remove(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type adapter for {@code} type that isn't {@code skipPast}. This
|
||||
* can be used for type adapters to compose other, simpler type adapters.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public <T> TypeAdapter<T> getNextAdapter(TypeAdapter.Factory skipPast, TypeToken<T> type) {
|
||||
boolean skipPastFound = false;
|
||||
|
||||
for (TypeAdapter.Factory factory : factories) {
|
||||
if (!skipPastFound) {
|
||||
if (factory == skipPast) {
|
||||
skipPastFound = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeAdapter<T> candidate = factory.create(this, type);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("This MiniGSON cannot serialize " + type);
|
||||
}
|
||||
|
||||
static class FutureTypeAdapter<T> extends TypeAdapter<T> {
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
public void setDelegate(TypeAdapter<T> typeAdapter) {
|
||||
if (delegate != null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
delegate = typeAdapter;
|
||||
}
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (delegate == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return delegate.read(reader);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (delegate == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
delegate.write(writer, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type adapter for {@code} type.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public <T> TypeAdapter<T> getAdapter(Class<T> type) {
|
||||
return getAdapter(TypeToken.get(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type adapters of this context in order of precedence.
|
||||
*/
|
||||
public List<TypeAdapter.Factory> getFactories() {
|
||||
return factories;
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private final List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||
boolean addDefaultFactories = true;
|
||||
|
||||
public Builder factory(TypeAdapter.Factory factory) {
|
||||
factories.add(factory);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withoutDefaultFactories() {
|
||||
this.addDefaultFactories = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder typeAdapter(final Class<T> type, final TypeAdapter<T> typeAdapter) {
|
||||
factories.add(TypeAdapters.newFactory(type, typeAdapter));
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder typeAdapter(TypeToken<T> type, TypeAdapter<T> typeAdapter) {
|
||||
factories.add(TypeAdapters.newFactory(type, typeAdapter));
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder typeHierarchyAdapter(Class<T> type, TypeAdapter<T> typeAdapter) {
|
||||
factories.add(TypeAdapters.newTypeHierarchyFactory(type, typeAdapter));
|
||||
return this;
|
||||
}
|
||||
|
||||
public MiniGson build() {
|
||||
return new MiniGson(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapts types whose static type is only 'Object'. Uses getClass() on
|
||||
* serialization and a primitive/Map/List on deserialization.
|
||||
*/
|
||||
public final class ObjectTypeAdapter extends TypeAdapter<Object> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
||||
if (type.getRawType() == Object.class) {
|
||||
return (TypeAdapter<T>) new ObjectTypeAdapter(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private final MiniGson miniGson;
|
||||
|
||||
private ObjectTypeAdapter(MiniGson miniGson) {
|
||||
this.miniGson = miniGson;
|
||||
}
|
||||
|
||||
@Override public Object read(JsonReader reader) throws IOException {
|
||||
JsonToken token = reader.peek();
|
||||
switch (token) {
|
||||
case BEGIN_ARRAY:
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
list.add(read(reader));
|
||||
}
|
||||
reader.endArray();
|
||||
return list;
|
||||
|
||||
case BEGIN_OBJECT:
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
map.put(reader.nextName(), read(reader));
|
||||
}
|
||||
reader.endObject();
|
||||
return map;
|
||||
|
||||
case STRING:
|
||||
return reader.nextString();
|
||||
|
||||
case NUMBER:
|
||||
return reader.nextDouble();
|
||||
|
||||
case BOOLEAN:
|
||||
return reader.nextBoolean();
|
||||
|
||||
case NULL:
|
||||
reader.nextNull();
|
||||
return null;
|
||||
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override public void write(JsonWriter writer, Object value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) miniGson.getAdapter(value.getClass());
|
||||
if (typeAdapter instanceof ObjectTypeAdapter) {
|
||||
writer.beginObject();
|
||||
writer.endObject();
|
||||
return;
|
||||
}
|
||||
|
||||
typeAdapter.write(writer, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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 com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
||||
final class Reflection {
|
||||
/**
|
||||
* Finds a compatible runtime type if it is more specific
|
||||
*/
|
||||
public static Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
|
||||
if (value != null
|
||||
&& (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {
|
||||
type = value.getClass();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user