This would be MCore4 v1.0.0
This commit is contained in:
42
src/com/massivecraft/mcore4/InternalListener.java
Normal file
42
src/com/massivecraft/mcore4/InternalListener.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.massivecraft.mcore4;
|
||||
|
||||
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.PlayerPreLoginEvent;
|
||||
|
||||
import com.massivecraft.mcore4.persist.IClassManager;
|
||||
import com.massivecraft.mcore4.persist.Persist;
|
||||
import com.massivecraft.mcore4.util.PlayerUtil;
|
||||
|
||||
public class InternalListener implements Listener
|
||||
{
|
||||
MCore p;
|
||||
|
||||
public InternalListener(MCore p)
|
||||
{
|
||||
this.p = p;
|
||||
Bukkit.getServer().getPluginManager().registerEvents(this, this.p);
|
||||
}
|
||||
|
||||
// TODO: Does this even trigger? If not we have an issue.
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/com/massivecraft/mcore4/Lang.java
Normal file
12
src/com/massivecraft/mcore4/Lang.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.massivecraft.mcore4;
|
||||
|
||||
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 arguments %s<b>.";
|
||||
public static final String commandToManyArgs2 = "<i>Use the command like this:";
|
||||
}
|
||||
135
src/com/massivecraft/mcore4/MCore.java
Normal file
135
src/com/massivecraft/mcore4/MCore.java
Normal file
@@ -0,0 +1,135 @@
|
||||
package com.massivecraft.mcore4;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.massivecraft.mcore4.cmd.Cmd;
|
||||
import com.massivecraft.mcore4.gson.InventoryTypeAdapter;
|
||||
import com.massivecraft.mcore4.gson.ItemStackAdapter;
|
||||
import com.massivecraft.mcore4.gson.MongoURIAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore4.lib.mongodb.MongoURI;
|
||||
import com.massivecraft.mcore4.persist.One;
|
||||
import com.massivecraft.mcore4.persist.Persist;
|
||||
import com.massivecraft.mcore4.util.LibLoader;
|
||||
import com.massivecraft.mcore4.util.PlayerUtil;
|
||||
import com.massivecraft.mcore4.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());
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// 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();
|
||||
|
||||
|
||||
|
||||
@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)
|
||||
.registerTypeAdapter(MongoURI.class, MongoURIAdapter.get())
|
||||
.registerTypeAdapter(ItemStack.class, new ItemStackAdapter())
|
||||
.registerTypeAdapter(Inventory.class, new InventoryTypeAdapter());
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// 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/mcore4/MPlugin.java
Normal file
117
src/com/massivecraft/mcore4/MPlugin.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package com.massivecraft.mcore4;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.massivecraft.mcore4.cmd.Cmd;
|
||||
import com.massivecraft.mcore4.lib.gson.Gson;
|
||||
import com.massivecraft.mcore4.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore4.persist.One;
|
||||
import com.massivecraft.mcore4.persist.Persist;
|
||||
import com.massivecraft.mcore4.util.LibLoader;
|
||||
import com.massivecraft.mcore4.util.Txt;
|
||||
|
||||
public abstract class MPlugin extends JavaPlugin implements Listener
|
||||
{
|
||||
// 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/mcore4/Predictate.java
Normal file
6
src/com/massivecraft/mcore4/Predictate.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.massivecraft.mcore4;
|
||||
|
||||
public interface Predictate<T>
|
||||
{
|
||||
public boolean apply(T type);
|
||||
}
|
||||
28
src/com/massivecraft/mcore4/cmd/BukkitGlueCommand.java
Normal file
28
src/com/massivecraft/mcore4/cmd/BukkitGlueCommand.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.massivecraft.mcore4.cmd;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.util.Txt;
|
||||
|
||||
public class BukkitGlueCommand extends Command
|
||||
{
|
||||
protected MCommand mcommand;
|
||||
public BukkitGlueCommand(MCommand mcommand)
|
||||
{
|
||||
super(mcommand.getAliases().get(0), mcommand.getDesc(), mcommand.getUseageTemplate(), mcommand.getAliases());
|
||||
this.mcommand = mcommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String commandLabel, String[] args)
|
||||
{
|
||||
if ( ! mcommand.p().isEnabled())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.mcommand.execute(sender, Txt.tokenizeArguments(Txt.implode(args, " ")));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
77
src/com/massivecraft/mcore4/cmd/Cmd.java
Normal file
77
src/com/massivecraft/mcore4/cmd/Cmd.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package com.massivecraft.mcore4.cmd;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore4.cmd.arg.AHBoolean;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHByte;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHDate;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHDouble;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHFloat;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHInteger;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHMaterial;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHPlayer;
|
||||
import com.massivecraft.mcore4.cmd.arg.AHWorld;
|
||||
import com.massivecraft.mcore4.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); }
|
||||
|
||||
/**
|
||||
* @deprecated As of MCore 3, replaced by by {@link MCommand#register()}
|
||||
*/
|
||||
@Deprecated
|
||||
public void addCommand(MCommand mcommand)
|
||||
{
|
||||
mcommand.register();
|
||||
}
|
||||
|
||||
public Cmd()
|
||||
{
|
||||
this.setArgHandler(Boolean.class, new AHBoolean());
|
||||
this.setArgHandler(Byte.class, new AHByte());
|
||||
this.setArgHandler(Double.class, new AHDouble());
|
||||
this.setArgHandler(Date.class, new AHDate());
|
||||
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());
|
||||
}
|
||||
|
||||
public static SimpleCommandMap getBukkitCommandMap()
|
||||
{
|
||||
CraftServer craftServer = (CraftServer)Bukkit.getServer();
|
||||
return craftServer.getCommandMap();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, Command> getKnownCommandsFromSimpleCommandMap(SimpleCommandMap scm)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field field = SimpleCommandMap.class.getDeclaredField("knownCommands");
|
||||
field.setAccessible(true);
|
||||
return (Map<String, Command>) field.get(scm);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/com/massivecraft/mcore4/cmd/HelpCommand.java
Normal file
57
src/com/massivecraft/mcore4/cmd/HelpCommand.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package com.massivecraft.mcore4.cmd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.massivecraft.mcore4.MPlugin;
|
||||
import com.massivecraft.mcore4.cmd.MCommand;
|
||||
import com.massivecraft.mcore4.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, 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;
|
||||
}
|
||||
}
|
||||
509
src/com/massivecraft/mcore4/cmd/MCommand.java
Normal file
509
src/com/massivecraft/mcore4/cmd/MCommand.java
Normal file
@@ -0,0 +1,509 @@
|
||||
package com.massivecraft.mcore4.cmd;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore4.Lang;
|
||||
import com.massivecraft.mcore4.MCore;
|
||||
import com.massivecraft.mcore4.MPlugin;
|
||||
import com.massivecraft.mcore4.cmd.arg.IArgHandler;
|
||||
import com.massivecraft.mcore4.cmd.req.IReq;
|
||||
import com.massivecraft.mcore4.cmd.req.ReqHasPerm;
|
||||
import com.massivecraft.mcore4.util.Perm;
|
||||
import com.massivecraft.mcore4.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;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// BUKKIT INTEGRATION
|
||||
// -------------------------------------------- //
|
||||
|
||||
public boolean register()
|
||||
{
|
||||
return register(false);
|
||||
}
|
||||
|
||||
public boolean register(boolean override)
|
||||
{
|
||||
BukkitGlueCommand bgc = new BukkitGlueCommand(this);
|
||||
SimpleCommandMap scm = Cmd.getBukkitCommandMap();
|
||||
|
||||
if (override)
|
||||
{
|
||||
// Our commands are more important than your commands :P
|
||||
Map<String, Command> knownCommands = Cmd.getKnownCommandsFromSimpleCommandMap(scm);
|
||||
String lowerLabel = bgc.getName().trim().toLowerCase();
|
||||
knownCommands.remove(lowerLabel);
|
||||
}
|
||||
|
||||
return scm.register("mcore", bgc);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCTORS AND EXECUTOR
|
||||
// -------------------------------------------- //
|
||||
|
||||
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.implodeCommaAndDot(theToMany, Txt.parse("<aqua>%s"), Txt.parse("<b>, "), Txt.parse("<b> and "), ""));
|
||||
msg(Lang.commandToManyArgs2);
|
||||
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, boolean onlyFirstAlias)
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
ret.append(Txt.parse("<c>"));
|
||||
ret.append('/');
|
||||
|
||||
boolean first = true;
|
||||
for (MCommand mc : commandChain)
|
||||
{
|
||||
if (first && onlyFirstAlias)
|
||||
{
|
||||
ret.append(mc.aliases.get(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(Txt.implode(mc.aliases, ","));
|
||||
}
|
||||
ret.append(' ');
|
||||
first = false;
|
||||
}
|
||||
|
||||
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(List<MCommand> commandChain, boolean addDesc)
|
||||
{
|
||||
return getUseageTemplate(commandChain, addDesc, false);
|
||||
}
|
||||
|
||||
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/mcore4/cmd/VisibilityMode.java
Normal file
9
src/com/massivecraft/mcore4/cmd/VisibilityMode.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.massivecraft.mcore4.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/mcore4/cmd/arg/AHBase.java
Normal file
22
src/com/massivecraft/mcore4/cmd/arg/AHBase.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.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/mcore4/cmd/arg/AHBoolean.java
Normal file
21
src/com/massivecraft/mcore4/cmd/arg/AHBoolean.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.massivecraft.mcore4.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/mcore4/cmd/arg/AHByte.java
Normal file
16
src/com/massivecraft/mcore4/cmd/arg/AHByte.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
public class AHByte extends AHPrimitive<Byte>
|
||||
{
|
||||
@Override
|
||||
protected String getPrimitiveName()
|
||||
{
|
||||
return "byte";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Byte unsafeConvert(String str) throws Exception
|
||||
{
|
||||
return Byte.parseByte(str);
|
||||
}
|
||||
}
|
||||
21
src/com/massivecraft/mcore4/cmd/arg/AHDate.java
Normal file
21
src/com/massivecraft/mcore4/cmd/arg/AHDate.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class AHDate extends AHPrimitive<Date>
|
||||
{
|
||||
protected static DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
@Override
|
||||
protected String getPrimitiveName()
|
||||
{
|
||||
return "YYYY-MM-DD date";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Date unsafeConvert(String str) throws Exception
|
||||
{
|
||||
return df.parse(str);
|
||||
}
|
||||
}
|
||||
16
src/com/massivecraft/mcore4/cmd/arg/AHDouble.java
Normal file
16
src/com/massivecraft/mcore4/cmd/arg/AHDouble.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore4.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/mcore4/cmd/arg/AHFloat.java
Normal file
16
src/com/massivecraft/mcore4/cmd/arg/AHFloat.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore4.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/mcore4/cmd/arg/AHInteger.java
Normal file
16
src/com/massivecraft/mcore4/cmd/arg/AHInteger.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore4.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/mcore4/cmd/arg/AHMaterial.java
Normal file
24
src/com/massivecraft/mcore4/cmd/arg/AHMaterial.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.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/mcore4/cmd/arg/AHPlayer.java
Normal file
39
src/com/massivecraft/mcore4/cmd/arg/AHPlayer.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore4.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/mcore4/cmd/arg/AHPlayerWrapper.java
Normal file
58
src/com/massivecraft/mcore4/cmd/arg/AHPlayerWrapper.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.MPlugin;
|
||||
import com.massivecraft.mcore4.persist.IClassManager;
|
||||
import com.massivecraft.mcore4.persist.Persist;
|
||||
import com.massivecraft.mcore4.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/mcore4/cmd/arg/AHPrimitive.java
Normal file
29
src/com/massivecraft/mcore4/cmd/arg/AHPrimitive.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.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/mcore4/cmd/arg/AHWorld.java
Normal file
26
src/com/massivecraft/mcore4/cmd/arg/AHWorld.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.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/mcore4/cmd/arg/IArgHandler.java
Normal file
16
src/com/massivecraft/mcore4/cmd/arg/IArgHandler.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore4.cmd.arg;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.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/mcore4/cmd/req/IReq.java
Normal file
14
src/com/massivecraft/mcore4/cmd/req/IReq.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.massivecraft.mcore4.cmd.req;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.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);
|
||||
}
|
||||
36
src/com/massivecraft/mcore4/cmd/req/ReqHasPerm.java
Normal file
36
src/com/massivecraft/mcore4/cmd/req/ReqHasPerm.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package com.massivecraft.mcore4.cmd.req;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.mcore4.cmd.MCommand;
|
||||
import com.massivecraft.mcore4.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);
|
||||
}
|
||||
|
||||
public static ReqHasPerm get(String perm)
|
||||
{
|
||||
return new ReqHasPerm(perm);
|
||||
}
|
||||
|
||||
}
|
||||
33
src/com/massivecraft/mcore4/cmd/req/ReqIsPlayer.java
Normal file
33
src/com/massivecraft/mcore4/cmd/req/ReqIsPlayer.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.massivecraft.mcore4.cmd.req;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore4.Lang;
|
||||
import com.massivecraft.mcore4.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;
|
||||
}
|
||||
|
||||
public static ReqIsPlayer get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
104
src/com/massivecraft/mcore4/gson/InventoryTypeAdapter.java
Normal file
104
src/com/massivecraft/mcore4/gson/InventoryTypeAdapter.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package com.massivecraft.mcore4.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.bukkit.craftbukkit.inventory.CraftInventoryCustom;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializer;
|
||||
|
||||
public class InventoryTypeAdapter implements JsonDeserializer<Inventory>, JsonSerializer<Inventory>
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// FIELD NAME CONSTANTS
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static final String SIZE = "size";
|
||||
|
||||
// -------------------------------------------- //
|
||||
// IMPLEMENTATION
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Inventory src, Type typeOfSrc, JsonSerializationContext context)
|
||||
{
|
||||
return serialize(src);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
return deserialize(json);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// STATIC LOGIC
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static JsonElement serialize(Inventory src)
|
||||
{
|
||||
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];
|
||||
JsonObject jsonItemStack = ItemStackAdapter.serialize(itemStack);
|
||||
if (jsonItemStack == null) continue;
|
||||
jsonInventory.add(String.valueOf(i), jsonItemStack);
|
||||
}
|
||||
|
||||
return jsonInventory;
|
||||
}
|
||||
|
||||
public static Inventory deserialize(JsonElement json)
|
||||
{
|
||||
if ( ! json.isJsonObject()) return null;
|
||||
JsonObject jsonInventory = json.getAsJsonObject();
|
||||
|
||||
if ( ! jsonInventory.has(SIZE)) return null;
|
||||
int size = jsonInventory.get(SIZE).getAsInt();
|
||||
|
||||
ItemStack[] itemStacks = new ItemStack[size];
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
// Fetch the jsonItemStack or mark it as empty and continue
|
||||
String stackIdx = String.valueOf(i);
|
||||
JsonElement jsonItemStack = jsonInventory.get(stackIdx);
|
||||
ItemStack itemStack = ItemStackAdapter.deserialize(jsonItemStack);
|
||||
itemStacks[i] = itemStack;
|
||||
}
|
||||
|
||||
Inventory ret = new CraftInventoryCustom(null, size, "items");
|
||||
ret.setContents(itemStacks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// UTIL
|
||||
// -------------------------------------------- //
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
122
src/com/massivecraft/mcore4/gson/ItemStackAdapter.java
Normal file
122
src/com/massivecraft/mcore4/gson/ItemStackAdapter.java
Normal file
@@ -0,0 +1,122 @@
|
||||
package com.massivecraft.mcore4.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializer;
|
||||
|
||||
public class ItemStackAdapter implements JsonDeserializer<ItemStack>, JsonSerializer<ItemStack>
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// FIELD NAME CONSTANTS
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static final String TYPE = "type";
|
||||
public static final String AMOUNT = "amount";
|
||||
public static final String DAMAGE = "damage";
|
||||
public static final String ENCHANTMENTS = "enchantments";
|
||||
|
||||
// -------------------------------------------- //
|
||||
// IMPLEMENTATION
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(ItemStack itemStack, Type typeOfSrc, JsonSerializationContext context)
|
||||
{
|
||||
return serialize(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
return deserialize(json);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// STATIC LOGIC
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static JsonObject serialize(ItemStack itemStack)
|
||||
{
|
||||
if (itemStack == null || itemStack.getTypeId() == 0 || itemStack.getAmount() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
JsonObject jsonItemStack = new JsonObject();
|
||||
|
||||
jsonItemStack.addProperty(ItemStackAdapter.TYPE, itemStack.getTypeId());
|
||||
|
||||
if (itemStack.getAmount() != 1)
|
||||
{
|
||||
jsonItemStack.addProperty(ItemStackAdapter.AMOUNT, itemStack.getAmount());
|
||||
}
|
||||
if (itemStack.getDurability() != 0) // Durability is a weird name since it is the amount of damage.
|
||||
{
|
||||
jsonItemStack.addProperty(ItemStackAdapter.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(ItemStackAdapter.ENCHANTMENTS, jsonEnchantments);
|
||||
}
|
||||
return jsonItemStack;
|
||||
}
|
||||
|
||||
public static ItemStack deserialize(JsonElement json)
|
||||
{
|
||||
if (json == null || ! json.isJsonObject()) return null;
|
||||
|
||||
JsonObject jsonItemStack = json.getAsJsonObject();
|
||||
|
||||
// Populate values
|
||||
int type = 0;
|
||||
int amount = 1;
|
||||
short damage = 0;
|
||||
|
||||
if (jsonItemStack.has(ItemStackAdapter.TYPE))
|
||||
{
|
||||
type = jsonItemStack.get(ItemStackAdapter.TYPE).getAsInt();
|
||||
}
|
||||
|
||||
if (jsonItemStack.has(ItemStackAdapter.AMOUNT))
|
||||
{
|
||||
amount = jsonItemStack.get(ItemStackAdapter.AMOUNT).getAsInt();
|
||||
}
|
||||
|
||||
if (jsonItemStack.has(ItemStackAdapter.DAMAGE))
|
||||
{
|
||||
damage = jsonItemStack.get(ItemStackAdapter.DAMAGE).getAsShort();
|
||||
}
|
||||
|
||||
// Create Non enchanted stack
|
||||
ItemStack stack = new ItemStack(type, amount, damage);
|
||||
|
||||
// Add enchantments if there are any
|
||||
if (jsonItemStack.has(ItemStackAdapter.ENCHANTMENTS))
|
||||
{
|
||||
JsonObject jsonEnchantments = jsonItemStack.get(ItemStackAdapter.ENCHANTMENTS).getAsJsonObject();
|
||||
for (Entry<String, JsonElement> enchantmentEntry: jsonEnchantments.entrySet())
|
||||
{
|
||||
int enchantmentId = Integer.valueOf(enchantmentEntry.getKey());
|
||||
Integer enchantmentLevel = Integer.valueOf(enchantmentEntry.getValue().getAsString());
|
||||
stack.addUnsafeEnchantment(Enchantment.getById(enchantmentId), enchantmentLevel);
|
||||
}
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
55
src/com/massivecraft/mcore4/gson/MongoURIAdapter.java
Normal file
55
src/com/massivecraft/mcore4/gson/MongoURIAdapter.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package com.massivecraft.mcore4.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore4.lib.mongodb.MongoURI;
|
||||
|
||||
public class MongoURIAdapter implements JsonDeserializer<MongoURI>, JsonSerializer<MongoURI>
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// IMPLEMENTATION
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(MongoURI mongoURI, Type typeOfSrc, JsonSerializationContext context)
|
||||
{
|
||||
return serialize(mongoURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoURI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
return deserialize(json);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// STATIC LOGIC
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static JsonElement serialize(MongoURI mongoURI)
|
||||
{
|
||||
return new JsonPrimitive(mongoURI.toString());
|
||||
}
|
||||
|
||||
public static MongoURI deserialize(JsonElement json)
|
||||
{
|
||||
return new MongoURI(json.getAsString());
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// INSTANCE
|
||||
// -------------------------------------------- //
|
||||
|
||||
protected static MongoURIAdapter instance = new MongoURIAdapter();
|
||||
public static MongoURIAdapter get()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
353
src/com/massivecraft/mcore4/lib/bson/BSON.java
Normal file
353
src/com/massivecraft/mcore4/lib/bson/BSON.java
Normal file
@@ -0,0 +1,353 @@
|
||||
// BSON.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.util.ClassMap;
|
||||
|
||||
public class BSON {
|
||||
|
||||
static final Logger LOGGER = Logger.getLogger( "org.bson.BSON" );
|
||||
|
||||
// ---- basics ----
|
||||
|
||||
public static final byte EOO = 0;
|
||||
public static final byte NUMBER = 1;
|
||||
public static final byte STRING = 2;
|
||||
public static final byte OBJECT = 3;
|
||||
public static final byte ARRAY = 4;
|
||||
public static final byte BINARY = 5;
|
||||
public static final byte UNDEFINED = 6;
|
||||
public static final byte OID = 7;
|
||||
public static final byte BOOLEAN = 8;
|
||||
public static final byte DATE = 9;
|
||||
public static final byte NULL = 10;
|
||||
public static final byte REGEX = 11;
|
||||
public static final byte REF = 12;
|
||||
public static final byte CODE = 13;
|
||||
public static final byte SYMBOL = 14;
|
||||
public static final byte CODE_W_SCOPE = 15;
|
||||
public static final byte NUMBER_INT = 16;
|
||||
public static final byte TIMESTAMP = 17;
|
||||
public static final byte NUMBER_LONG = 18;
|
||||
|
||||
public static final byte MINKEY = -1;
|
||||
public static final byte MAXKEY = 127;
|
||||
|
||||
// --- binary types
|
||||
/*
|
||||
these are binary types
|
||||
so the format would look like
|
||||
<BINARY><name><BINARY_TYPE><...>
|
||||
*/
|
||||
|
||||
public static final byte B_GENERAL = 0;
|
||||
public static final byte B_FUNC = 1;
|
||||
public static final byte B_BINARY = 2;
|
||||
public static final byte B_UUID = 3;
|
||||
|
||||
// ---- regular expression handling ----
|
||||
|
||||
/** Converts a string of regular expression flags from the database in Java regular
|
||||
* expression flags.
|
||||
* @param flags flags from database
|
||||
* @return the Java flags
|
||||
*/
|
||||
public static int regexFlags( String flags ){
|
||||
int fint = 0;
|
||||
if ( flags == null || flags.length() == 0 )
|
||||
return fint;
|
||||
|
||||
flags = flags.toLowerCase();
|
||||
|
||||
for( int i=0; i<flags.length(); i++ ) {
|
||||
RegexFlag flag = RegexFlag.getByCharacter( flags.charAt( i ) );
|
||||
if( flag != null ) {
|
||||
fint |= flag.javaFlag;
|
||||
if( flag.unsupported != null )
|
||||
_warnUnsupportedRegex( flag.unsupported );
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "unrecognized flag ["+flags.charAt( i ) + "] " + (int)flags.charAt(i) );
|
||||
}
|
||||
}
|
||||
return fint;
|
||||
}
|
||||
|
||||
public static int regexFlag( char c ){
|
||||
RegexFlag flag = RegexFlag.getByCharacter( c );
|
||||
if ( flag == null )
|
||||
throw new IllegalArgumentException( "unrecognized flag [" + c + "]" );
|
||||
|
||||
if ( flag.unsupported != null ){
|
||||
_warnUnsupportedRegex( flag.unsupported );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return flag.javaFlag;
|
||||
}
|
||||
|
||||
/** Converts Java regular expression flags into a string of flags for the database
|
||||
* @param flags Java flags
|
||||
* @return the flags for the database
|
||||
*/
|
||||
public static String regexFlags( int flags ){
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
for( RegexFlag flag : RegexFlag.values() ) {
|
||||
if( ( flags & flag.javaFlag ) > 0 ) {
|
||||
buf.append( flag.flagChar );
|
||||
flags -= flag.javaFlag;
|
||||
}
|
||||
}
|
||||
|
||||
if( flags > 0 )
|
||||
throw new IllegalArgumentException( "some flags could not be recognized." );
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static enum RegexFlag {
|
||||
CANON_EQ( Pattern.CANON_EQ, 'c', "Pattern.CANON_EQ" ),
|
||||
UNIX_LINES(Pattern.UNIX_LINES, 'd', "Pattern.UNIX_LINES" ),
|
||||
GLOBAL( GLOBAL_FLAG, 'g', null ),
|
||||
CASE_INSENSITIVE( Pattern.CASE_INSENSITIVE, 'i', null ),
|
||||
MULTILINE(Pattern.MULTILINE, 'm', null ),
|
||||
DOTALL( Pattern.DOTALL, 's', "Pattern.DOTALL" ),
|
||||
LITERAL( Pattern.LITERAL, 't', "Pattern.LITERAL" ),
|
||||
UNICODE_CASE( Pattern.UNICODE_CASE, 'u', "Pattern.UNICODE_CASE" ),
|
||||
COMMENTS( Pattern.COMMENTS, 'x', null );
|
||||
|
||||
private static final Map<Character, RegexFlag> byCharacter = new HashMap<Character, RegexFlag>();
|
||||
|
||||
static {
|
||||
for (RegexFlag flag : values()) {
|
||||
byCharacter.put(flag.flagChar, flag);
|
||||
}
|
||||
}
|
||||
|
||||
public static RegexFlag getByCharacter(char ch) {
|
||||
return byCharacter.get(ch);
|
||||
}
|
||||
public final int javaFlag;
|
||||
public final char flagChar;
|
||||
public final String unsupported;
|
||||
|
||||
RegexFlag( int f, char ch, String u ) {
|
||||
javaFlag = f;
|
||||
flagChar = ch;
|
||||
unsupported = u;
|
||||
}
|
||||
}
|
||||
|
||||
private static void _warnUnsupportedRegex( String flag ) {
|
||||
LOGGER.info( "flag " + flag + " not supported by db." );
|
||||
}
|
||||
|
||||
private static final int GLOBAL_FLAG = 256;
|
||||
|
||||
// --- (en|de)coding hooks -----
|
||||
|
||||
public static boolean hasDecodeHooks() { return _decodeHooks; }
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static void addEncodingHook( Class c , Transformer t ){
|
||||
_encodeHooks = true;
|
||||
List<Transformer> l = _encodingHooks.get( c );
|
||||
if ( l == null ){
|
||||
l = new CopyOnWriteArrayList<Transformer>();
|
||||
_encodingHooks.put( c , l );
|
||||
}
|
||||
l.add( t );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static void addDecodingHook( Class c , Transformer t ){
|
||||
_decodeHooks = true;
|
||||
List<Transformer> l = _decodingHooks.get( c );
|
||||
if ( l == null ){
|
||||
l = new CopyOnWriteArrayList<Transformer>();
|
||||
_decodingHooks.put( c , l );
|
||||
}
|
||||
l.add( t );
|
||||
}
|
||||
|
||||
public static Object applyEncodingHooks( Object o ){
|
||||
if ( ! _anyHooks() )
|
||||
return o;
|
||||
|
||||
if ( _encodingHooks.size() == 0 || o == null )
|
||||
return o;
|
||||
List<Transformer> l = _encodingHooks.get( o.getClass() );
|
||||
if ( l != null )
|
||||
for ( Transformer t : l )
|
||||
o = t.transform( o );
|
||||
return o;
|
||||
}
|
||||
|
||||
public static Object applyDecodingHooks( Object o ){
|
||||
if ( ! _anyHooks() || o == null )
|
||||
return o;
|
||||
|
||||
List<Transformer> l = _decodingHooks.get( o.getClass() );
|
||||
if ( l != null )
|
||||
for ( Transformer t : l )
|
||||
o = t.transform( o );
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoding hook(s) associated with the specified class
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static List<Transformer> getEncodingHooks( Class c ){
|
||||
return _encodingHooks.get( c );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears *all* encoding hooks.
|
||||
*/
|
||||
public static void clearEncodingHooks(){
|
||||
_encodeHooks = false;
|
||||
_encodingHooks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all encoding hooks for a specific class.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static void removeEncodingHooks( Class c ){
|
||||
_encodingHooks.remove( c );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific encoding hook for a specific class.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static void removeEncodingHook( Class c , Transformer t ){
|
||||
getEncodingHooks( c ).remove( t );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the decoding hook(s) associated with the specific class
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static List<Transformer> getDecodingHooks( Class c ){
|
||||
return _decodingHooks.get( c );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears *all* decoding hooks.
|
||||
*/
|
||||
public static void clearDecodingHooks(){
|
||||
_decodeHooks = false;
|
||||
_decodingHooks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all decoding hooks for a specific class.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static void removeDecodingHooks( Class c ){
|
||||
_decodingHooks.remove( c );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific encoding hook for a specific class.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static void removeDecodingHook( Class c , Transformer t ){
|
||||
getDecodingHooks( c ).remove( t );
|
||||
}
|
||||
|
||||
|
||||
public static void clearAllHooks(){
|
||||
clearEncodingHooks();
|
||||
clearDecodingHooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any encoding or decoding hooks are loaded.
|
||||
*/
|
||||
private static boolean _anyHooks(){
|
||||
return _encodeHooks || _decodeHooks;
|
||||
}
|
||||
|
||||
private static boolean _encodeHooks = false;
|
||||
private static boolean _decodeHooks = false;
|
||||
static ClassMap<List<Transformer>> _encodingHooks =
|
||||
new ClassMap<List<Transformer>>();
|
||||
|
||||
static ClassMap<List<Transformer>> _decodingHooks =
|
||||
new ClassMap<List<Transformer>>();
|
||||
|
||||
static protected Charset _utf8 = Charset.forName( "UTF-8" );
|
||||
|
||||
// ----- static encode/decode -----
|
||||
|
||||
public static byte[] encode( BSONObject o ){
|
||||
BSONEncoder e = _staticEncoder.get();
|
||||
try {
|
||||
return e.encode( o );
|
||||
}
|
||||
finally {
|
||||
e.done();
|
||||
}
|
||||
}
|
||||
|
||||
public static BSONObject decode( byte[] b ){
|
||||
BSONDecoder d = _staticDecoder.get();
|
||||
return d.readObject( b );
|
||||
}
|
||||
|
||||
static ThreadLocal<BSONEncoder> _staticEncoder = new ThreadLocal<BSONEncoder>(){
|
||||
protected BSONEncoder initialValue(){
|
||||
return new BasicBSONEncoder();
|
||||
}
|
||||
};
|
||||
|
||||
static ThreadLocal<BSONDecoder> _staticDecoder = new ThreadLocal<BSONDecoder>(){
|
||||
protected BSONDecoder initialValue(){
|
||||
return new BasicBSONDecoder();
|
||||
}
|
||||
};
|
||||
|
||||
// --- coercing ---
|
||||
|
||||
public static int toInt( Object o ){
|
||||
if ( o == null )
|
||||
throw new NullPointerException( "can't be null" );
|
||||
|
||||
if ( o instanceof Number )
|
||||
return ((Number)o).intValue();
|
||||
|
||||
if ( o instanceof Boolean )
|
||||
return ((Boolean)o) ? 1 : 0;
|
||||
|
||||
throw new IllegalArgumentException( "can't convert: " + o.getClass().getName() + " to int" );
|
||||
}
|
||||
}
|
||||
70
src/com/massivecraft/mcore4/lib/bson/BSONCallback.java
Normal file
70
src/com/massivecraft/mcore4/lib/bson/BSONCallback.java
Normal file
@@ -0,0 +1,70 @@
|
||||
// BSONCallback.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.types.ObjectId;
|
||||
|
||||
public interface BSONCallback {
|
||||
|
||||
void objectStart();
|
||||
void objectStart(String name);
|
||||
void objectStart(boolean array);
|
||||
Object objectDone();
|
||||
|
||||
void reset();
|
||||
Object get();
|
||||
BSONCallback createBSONCallback();
|
||||
|
||||
void arrayStart();
|
||||
void arrayStart(String name);
|
||||
Object arrayDone();
|
||||
|
||||
void gotNull( String name );
|
||||
void gotUndefined( String name );
|
||||
void gotMinKey( String name );
|
||||
void gotMaxKey( String name );
|
||||
|
||||
void gotBoolean( String name , boolean v );
|
||||
void gotDouble( String name , double v );
|
||||
void gotInt( String name , int v );
|
||||
void gotLong( String name , long v );
|
||||
|
||||
void gotDate( String name , long millis );
|
||||
void gotString( String name , String v );
|
||||
void gotSymbol( String name , String v );
|
||||
void gotRegex( String name , String pattern , String flags );
|
||||
|
||||
void gotTimestamp( String name , int time , int inc );
|
||||
void gotObjectId( String name , ObjectId id );
|
||||
void gotDBRef( String name , String ns , ObjectId id );
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
void gotBinaryArray( String name , byte[] data );
|
||||
void gotBinary( String name , byte type , byte[] data );
|
||||
/**
|
||||
* subtype 3
|
||||
*/
|
||||
void gotUUID( String name , long part1, long part2);
|
||||
|
||||
void gotCode( String name , String code );
|
||||
void gotCodeWScope( String name , String code , Object scope );
|
||||
}
|
||||
34
src/com/massivecraft/mcore4/lib/bson/BSONDecoder.java
Normal file
34
src/com/massivecraft/mcore4/lib/bson/BSONDecoder.java
Normal file
@@ -0,0 +1,34 @@
|
||||
// BSONDecoder.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface BSONDecoder {
|
||||
|
||||
public BSONObject readObject( byte[] b );
|
||||
|
||||
public BSONObject readObject( InputStream in ) throws IOException;
|
||||
|
||||
public int decode( byte[] b , BSONCallback callback );
|
||||
|
||||
public int decode( InputStream in , BSONCallback callback ) throws IOException;
|
||||
|
||||
}
|
||||
27
src/com/massivecraft/mcore4/lib/bson/BSONEncoder.java
Normal file
27
src/com/massivecraft/mcore4/lib/bson/BSONEncoder.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2008 - 2011 10gen, Inc. <http://10gen.com>
|
||||
*
|
||||
* 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.mcore4.lib.bson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.*;
|
||||
|
||||
|
||||
public interface BSONEncoder {
|
||||
public byte[] encode( BSONObject o );
|
||||
|
||||
public int putObject( BSONObject o );
|
||||
|
||||
public void done();
|
||||
|
||||
void set( OutputBuffer out );
|
||||
}
|
||||
73
src/com/massivecraft/mcore4/lib/bson/BSONException.java
Normal file
73
src/com/massivecraft/mcore4/lib/bson/BSONException.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (C) 2011, 10gen 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.mcore4.lib.bson;
|
||||
|
||||
/**
|
||||
* A general runtime exception raised in BSON processing.
|
||||
*/
|
||||
public class BSONException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -4415279469780082174L;
|
||||
|
||||
/**
|
||||
* @param msg The error message.
|
||||
*/
|
||||
public BSONException( final String msg ) {
|
||||
super( msg );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param errorCode The error code.
|
||||
* @param msg The error message.
|
||||
*/
|
||||
public BSONException( final int errorCode, final String msg ) {
|
||||
super( msg );
|
||||
_errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg The error message.
|
||||
* @param t The throwable cause.
|
||||
*/
|
||||
public BSONException( final String msg , final Throwable t ) {
|
||||
super( msg, t );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param errorCode The error code.
|
||||
* @param msg The error message.
|
||||
* @param t The throwable cause.
|
||||
*/
|
||||
public BSONException( final int errorCode, final String msg, final Throwable t ) {
|
||||
super( msg, t );
|
||||
_errorCode = errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error code.
|
||||
* @return The error code.
|
||||
*/
|
||||
public Integer getErrorCode() { return _errorCode; }
|
||||
|
||||
/**
|
||||
* Returns true if the error code is set (i.e., not null).
|
||||
*/
|
||||
public boolean hasErrorCode() { return (_errorCode != null); }
|
||||
|
||||
private Integer _errorCode = null;
|
||||
}
|
||||
|
||||
24
src/com/massivecraft/mcore4/lib/bson/BSONLazyDecoder.java
Normal file
24
src/com/massivecraft/mcore4/lib/bson/BSONLazyDecoder.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author antoine
|
||||
*/
|
||||
public class BSONLazyDecoder {
|
||||
|
||||
}
|
||||
93
src/com/massivecraft/mcore4/lib/bson/BSONObject.java
Normal file
93
src/com/massivecraft/mcore4/lib/bson/BSONObject.java
Normal file
@@ -0,0 +1,93 @@
|
||||
// BSONObject.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A key-value map that can be saved to the database.
|
||||
*/
|
||||
public interface BSONObject {
|
||||
|
||||
/**
|
||||
* Sets a name/value pair in this object.
|
||||
* @param key Name to set
|
||||
* @param v Corresponding value
|
||||
* @return <tt>v</tt>
|
||||
*/
|
||||
public Object put( String key , Object v );
|
||||
|
||||
/**
|
||||
* Sets all key/value pairs from an object into this object
|
||||
* @param o the object
|
||||
*/
|
||||
public void putAll( BSONObject o );
|
||||
|
||||
/**
|
||||
* Sets all key/value pairs from a map into this object
|
||||
* @param m the map
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void putAll( Map m );
|
||||
|
||||
/**
|
||||
* Gets a field from this object by a given name.
|
||||
* @param key The name of the field fetch
|
||||
* @return The field, if found
|
||||
*/
|
||||
public Object get( String key );
|
||||
|
||||
/**
|
||||
* Returns a map representing this BSONObject.
|
||||
* @return the map
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Map toMap();
|
||||
|
||||
/**
|
||||
* Removes a field with a given name from this object.
|
||||
* @param key The name of the field to remove
|
||||
* @return The value removed from this object
|
||||
*/
|
||||
public Object removeField( String key );
|
||||
|
||||
/**
|
||||
* Deprecated
|
||||
* @param s
|
||||
* @return True if the key is present
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean containsKey( String s );
|
||||
|
||||
/**
|
||||
* Checks if this object contains a field with the given name.
|
||||
* @param s Field name for which to check
|
||||
* @return True if the field is present
|
||||
*/
|
||||
public boolean containsField(String s);
|
||||
|
||||
/**
|
||||
* Returns this object's fields' names
|
||||
* @return The names of the fields in this object
|
||||
*/
|
||||
public Set<String> keySet();
|
||||
}
|
||||
|
||||
206
src/com/massivecraft/mcore4/lib/bson/BasicBSONCallback.java
Normal file
206
src/com/massivecraft/mcore4/lib/bson/BasicBSONCallback.java
Normal file
@@ -0,0 +1,206 @@
|
||||
// BasicBSONCallback.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.types.*;
|
||||
|
||||
public class BasicBSONCallback implements BSONCallback {
|
||||
|
||||
public BasicBSONCallback(){
|
||||
reset();
|
||||
}
|
||||
|
||||
public BSONObject create(){
|
||||
return new BasicBSONObject();
|
||||
}
|
||||
|
||||
protected BSONObject createList() {
|
||||
return new BasicBSONList();
|
||||
}
|
||||
|
||||
public BSONCallback createBSONCallback(){
|
||||
return new BasicBSONCallback();
|
||||
}
|
||||
|
||||
public BSONObject create( boolean array , List<String> path ){
|
||||
if ( array )
|
||||
return createList();
|
||||
return create();
|
||||
}
|
||||
|
||||
public void objectStart(){
|
||||
if ( _stack.size() > 0 )
|
||||
throw new IllegalStateException( "something is wrong" );
|
||||
|
||||
objectStart(false);
|
||||
}
|
||||
|
||||
public void objectStart(boolean array){
|
||||
_root = create(array, null);
|
||||
_stack.add( (BSONObject)_root );
|
||||
}
|
||||
|
||||
public void objectStart(String name){
|
||||
objectStart( false , name );
|
||||
}
|
||||
|
||||
public void objectStart(boolean array, String name){
|
||||
_nameStack.addLast( name );
|
||||
final BSONObject o = create( array , _nameStack );
|
||||
_stack.getLast().put( name , o);
|
||||
_stack.addLast( o );
|
||||
}
|
||||
|
||||
public Object objectDone(){
|
||||
final BSONObject o =_stack.removeLast();
|
||||
if ( _nameStack.size() > 0 )
|
||||
_nameStack.removeLast();
|
||||
else if ( _stack.size() > 0 )
|
||||
throw new IllegalStateException( "something is wrong" );
|
||||
|
||||
return !BSON.hasDecodeHooks() ? o : (BSONObject)BSON.applyDecodingHooks(o);
|
||||
}
|
||||
|
||||
public void arrayStart(){
|
||||
objectStart( true );
|
||||
}
|
||||
|
||||
public void arrayStart(String name){
|
||||
objectStart( true , name );
|
||||
}
|
||||
|
||||
public Object arrayDone(){
|
||||
return objectDone();
|
||||
}
|
||||
|
||||
public void gotNull( String name ){
|
||||
cur().put( name , null );
|
||||
}
|
||||
|
||||
public void gotUndefined( String name ) { }
|
||||
|
||||
public void gotMinKey( String name ){
|
||||
cur().put( name , new MinKey() );
|
||||
}
|
||||
|
||||
public void gotMaxKey( String name ){
|
||||
cur().put( name , new MaxKey() );
|
||||
}
|
||||
|
||||
public void gotBoolean( String name , boolean v ){
|
||||
_put( name , v );
|
||||
}
|
||||
|
||||
public void gotDouble( final String name , final double v ){
|
||||
_put( name , v );
|
||||
}
|
||||
|
||||
public void gotInt( final String name , final int v ){
|
||||
_put( name , v );
|
||||
}
|
||||
|
||||
public void gotLong( final String name , final long v ){
|
||||
_put( name , v );
|
||||
}
|
||||
|
||||
public void gotDate( String name , long millis ){
|
||||
_put( name , new Date( millis ) );
|
||||
}
|
||||
public void gotRegex( String name , String pattern , String flags ){
|
||||
_put( name , Pattern.compile( pattern , BSON.regexFlags( flags ) ) );
|
||||
}
|
||||
|
||||
public void gotString( final String name , final String v ){
|
||||
_put( name , v );
|
||||
}
|
||||
public void gotSymbol( String name , String v ){
|
||||
_put( name , v );
|
||||
}
|
||||
|
||||
public void gotTimestamp( String name , int time , int inc ){
|
||||
_put( name , new BSONTimestamp( time , inc ) );
|
||||
}
|
||||
public void gotObjectId( String name , ObjectId id ){
|
||||
_put( name , id );
|
||||
}
|
||||
public void gotDBRef( String name , String ns , ObjectId id ){
|
||||
_put( name , new BasicBSONObject( "$ns" , ns ).append( "$id" , id ) );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void gotBinaryArray( String name , byte[] data ){
|
||||
gotBinary( name, BSON.B_GENERAL, data );
|
||||
}
|
||||
|
||||
public void gotBinary( String name , byte type , byte[] data ){
|
||||
if( type == BSON.B_GENERAL || type == BSON.B_BINARY )
|
||||
_put( name , data );
|
||||
else
|
||||
_put( name , new Binary( type , data ) );
|
||||
}
|
||||
|
||||
public void gotUUID( String name , long part1, long part2){
|
||||
_put( name , new UUID(part1, part2) );
|
||||
}
|
||||
|
||||
public void gotCode( String name , String code ){
|
||||
_put( name , new Code( code ) );
|
||||
}
|
||||
|
||||
public void gotCodeWScope( String name , String code , Object scope ){
|
||||
_put( name , new CodeWScope( code, (BSONObject)scope ) );
|
||||
}
|
||||
|
||||
protected void _put( final String name , final Object o ){
|
||||
cur().put( name , !BSON.hasDecodeHooks() ? o : BSON.applyDecodingHooks( o ) );
|
||||
}
|
||||
|
||||
protected BSONObject cur(){
|
||||
return _stack.getLast();
|
||||
}
|
||||
|
||||
protected String curName(){
|
||||
return (!_nameStack.isEmpty()) ? _nameStack.getLast() : null;
|
||||
}
|
||||
|
||||
public Object get(){
|
||||
return _root;
|
||||
}
|
||||
|
||||
protected void setRoot(Object o) {
|
||||
_root = o;
|
||||
}
|
||||
|
||||
protected boolean isStackEmpty() {
|
||||
return _stack.size() < 1;
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
_root = null;
|
||||
_stack.clear();
|
||||
_nameStack.clear();
|
||||
}
|
||||
|
||||
private Object _root;
|
||||
private final LinkedList<BSONObject> _stack = new LinkedList<BSONObject>();
|
||||
private final LinkedList<String> _nameStack = new LinkedList<String>();
|
||||
}
|
||||
527
src/com/massivecraft/mcore4/lib/bson/BasicBSONDecoder.java
Normal file
527
src/com/massivecraft/mcore4/lib/bson/BasicBSONDecoder.java
Normal file
@@ -0,0 +1,527 @@
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.PoolOutputBuffer;
|
||||
import com.massivecraft.mcore4.lib.bson.types.ObjectId;
|
||||
|
||||
|
||||
/**
|
||||
* Basic implementation of BSONDecoder interface that creates BasicBSONObject instances
|
||||
*/
|
||||
public class BasicBSONDecoder implements BSONDecoder {
|
||||
public BSONObject readObject( byte[] b ){
|
||||
try {
|
||||
return readObject( new ByteArrayInputStream( b ) );
|
||||
}
|
||||
catch ( IOException ioe ){
|
||||
throw new BSONException( "should be impossible" , ioe );
|
||||
}
|
||||
}
|
||||
|
||||
public BSONObject readObject( InputStream in )
|
||||
throws IOException {
|
||||
BasicBSONCallback c = new BasicBSONCallback();
|
||||
decode( in , c );
|
||||
return (BSONObject)c.get();
|
||||
}
|
||||
|
||||
public int decode( byte[] b , BSONCallback callback ){
|
||||
try {
|
||||
return _decode( new BSONInput( new ByteArrayInputStream(b) ) , callback );
|
||||
}
|
||||
catch ( IOException ioe ){
|
||||
throw new BSONException( "should be impossible" , ioe );
|
||||
}
|
||||
}
|
||||
|
||||
public int decode( InputStream in , BSONCallback callback )
|
||||
throws IOException {
|
||||
return _decode( new BSONInput( in ) , callback );
|
||||
}
|
||||
|
||||
private int _decode( BSONInput in , BSONCallback callback )
|
||||
throws IOException {
|
||||
|
||||
if ( _in != null || _callback != null )
|
||||
throw new IllegalStateException( "not ready" );
|
||||
|
||||
_in = in;
|
||||
_callback = callback;
|
||||
|
||||
if ( in.numRead() != 0 )
|
||||
throw new IllegalArgumentException( "i'm confused" );
|
||||
|
||||
try {
|
||||
|
||||
final int len = _in.readInt();
|
||||
|
||||
_in.setMax(len);
|
||||
|
||||
_callback.objectStart();
|
||||
while ( decodeElement() );
|
||||
_callback.objectDone();
|
||||
|
||||
if ( _in.numRead() != len )
|
||||
throw new IllegalArgumentException( "bad data. lengths don't match read:" + _in.numRead() + " != len:" + len );
|
||||
|
||||
return len;
|
||||
}
|
||||
finally {
|
||||
_in = null;
|
||||
_callback = null;
|
||||
}
|
||||
}
|
||||
|
||||
int decode( boolean first )
|
||||
throws IOException {
|
||||
|
||||
final int start = _in.numRead();
|
||||
|
||||
final int len = _in.readInt();
|
||||
if ( first )
|
||||
_in.setMax(len);
|
||||
|
||||
_callback.objectStart();
|
||||
while ( decodeElement() );
|
||||
_callback.objectDone();
|
||||
|
||||
final int read = _in.numRead() - start;
|
||||
|
||||
if ( read != len ){
|
||||
//throw new IllegalArgumentException( "bad data. lengths don't match " + read + " != " + len );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
boolean decodeElement()
|
||||
throws IOException {
|
||||
|
||||
final byte type = _in.read();
|
||||
|
||||
if ( type == EOO )
|
||||
return false;
|
||||
|
||||
String name = _in.readCStr();
|
||||
|
||||
switch ( type ){
|
||||
case NULL:
|
||||
_callback.gotNull( name );
|
||||
break;
|
||||
|
||||
case UNDEFINED:
|
||||
_callback.gotUndefined( name );
|
||||
break;
|
||||
|
||||
case BOOLEAN:
|
||||
_callback.gotBoolean( name , _in.read() > 0 );
|
||||
break;
|
||||
|
||||
case NUMBER:
|
||||
_callback.gotDouble( name , _in.readDouble() );
|
||||
break;
|
||||
|
||||
case NUMBER_INT:
|
||||
_callback.gotInt( name , _in.readInt() );
|
||||
break;
|
||||
|
||||
case NUMBER_LONG:
|
||||
_callback.gotLong( name , _in.readLong() );
|
||||
break;
|
||||
|
||||
case SYMBOL:
|
||||
_callback.gotSymbol( name , _in.readUTF8String() );
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
_callback.gotString(name, _in.readUTF8String() );
|
||||
break;
|
||||
|
||||
case OID:
|
||||
// OID is stored as big endian
|
||||
_callback.gotObjectId( name , new ObjectId( _in.readIntBE() , _in.readIntBE() , _in.readIntBE() ) );
|
||||
break;
|
||||
|
||||
case REF:
|
||||
_in.readInt(); // length of ctring that follows
|
||||
String ns = _in.readCStr();
|
||||
ObjectId theOID = new ObjectId( _in.readInt() , _in.readInt() , _in.readInt() );
|
||||
_callback.gotDBRef( name , ns , theOID );
|
||||
break;
|
||||
|
||||
case DATE:
|
||||
_callback.gotDate( name , _in.readLong() );
|
||||
break;
|
||||
|
||||
case REGEX:
|
||||
_callback.gotRegex( name , _in.readCStr() , _in.readCStr() );
|
||||
break;
|
||||
|
||||
case BINARY:
|
||||
_binary( name );
|
||||
break;
|
||||
|
||||
case CODE:
|
||||
_callback.gotCode( name , _in.readUTF8String() );
|
||||
break;
|
||||
|
||||
case CODE_W_SCOPE:
|
||||
_in.readInt();
|
||||
_callback.gotCodeWScope( name , _in.readUTF8String() , _readBasicObject() );
|
||||
|
||||
break;
|
||||
|
||||
case ARRAY:
|
||||
_in.readInt(); // total size - we don't care....
|
||||
|
||||
_callback.arrayStart( name );
|
||||
while ( decodeElement() );
|
||||
_callback.arrayDone();
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case OBJECT:
|
||||
_in.readInt(); // total size - we don't care....
|
||||
|
||||
_callback.objectStart( name );
|
||||
while ( decodeElement() );
|
||||
_callback.objectDone();
|
||||
|
||||
break;
|
||||
|
||||
case TIMESTAMP:
|
||||
int i = _in.readInt();
|
||||
int time = _in.readInt();
|
||||
_callback.gotTimestamp( name , time , i );
|
||||
break;
|
||||
|
||||
case MINKEY:
|
||||
_callback.gotMinKey( name );
|
||||
break;
|
||||
|
||||
case MAXKEY:
|
||||
_callback.gotMaxKey( name );
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnsupportedOperationException( "BSONDecoder doesn't understand type : " + type + " name: " + name );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void _binary( final String name )
|
||||
throws IOException {
|
||||
final int totalLen = _in.readInt();
|
||||
final byte bType = _in.read();
|
||||
|
||||
switch ( bType ){
|
||||
case B_GENERAL: {
|
||||
final byte[] data = new byte[totalLen];
|
||||
_in.fill( data );
|
||||
_callback.gotBinary( name, bType, data );
|
||||
return;
|
||||
}
|
||||
case B_BINARY:
|
||||
final int len = _in.readInt();
|
||||
if ( len + 4 != totalLen )
|
||||
throw new IllegalArgumentException( "bad data size subtype 2 len: " + len + " totalLen: " + totalLen );
|
||||
|
||||
final byte [] data = new byte[len];
|
||||
_in.fill( data );
|
||||
_callback.gotBinary( name , bType , data );
|
||||
return;
|
||||
case B_UUID:
|
||||
if ( totalLen != 16 )
|
||||
throw new IllegalArgumentException( "bad data size subtype 3 len: " + totalLen + " != 16");
|
||||
|
||||
final long part1 = _in.readLong();
|
||||
final long part2 = _in.readLong();
|
||||
_callback.gotUUID(name, part1, part2);
|
||||
return;
|
||||
}
|
||||
|
||||
final byte [] data = new byte[totalLen];
|
||||
_in.fill( data );
|
||||
|
||||
_callback.gotBinary( name , bType , data );
|
||||
}
|
||||
|
||||
Object _readBasicObject()
|
||||
throws IOException {
|
||||
_in.readInt();
|
||||
|
||||
final BSONCallback save = _callback;
|
||||
final BSONCallback _basic = _callback.createBSONCallback();
|
||||
_callback = _basic;
|
||||
_basic.reset();
|
||||
_basic.objectStart(false);
|
||||
|
||||
while( decodeElement() );
|
||||
_callback = save;
|
||||
return _basic.get();
|
||||
}
|
||||
|
||||
protected class BSONInput {
|
||||
|
||||
public BSONInput(final InputStream in){
|
||||
_raw = in;
|
||||
_read = 0;
|
||||
|
||||
_pos = 0;
|
||||
_len = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ensure that there are num bytes to read
|
||||
* _pos is where to start reading from
|
||||
* @return where to start reading from
|
||||
*/
|
||||
protected int _need( final int num )
|
||||
throws IOException {
|
||||
|
||||
//System.out.println( "p: " + _pos + " l: " + _len + " want: " + num );
|
||||
|
||||
if ( _len - _pos >= num ){
|
||||
final int ret = _pos;
|
||||
_pos += num;
|
||||
_read += num;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ( num >= _inputBuffer.length )
|
||||
throw new IllegalArgumentException( "you can't need that much" );
|
||||
|
||||
final int remaining = _len - _pos;
|
||||
if ( _pos > 0 ){
|
||||
System.arraycopy( _inputBuffer , _pos , _inputBuffer , 0 , remaining );
|
||||
|
||||
_pos = 0;
|
||||
_len = remaining;
|
||||
}
|
||||
|
||||
// read as much as possible into buffer
|
||||
int maxToRead = Math.min( _max - _read - remaining , _inputBuffer.length - _len );
|
||||
while ( maxToRead > 0 ){
|
||||
int x = _raw.read( _inputBuffer , _len , maxToRead);
|
||||
if ( x <= 0 )
|
||||
throw new IOException( "unexpected EOF" );
|
||||
maxToRead -= x;
|
||||
_len += x;
|
||||
}
|
||||
|
||||
int ret = _pos;
|
||||
_pos += num;
|
||||
_read += num;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int readInt()
|
||||
throws IOException {
|
||||
return com.massivecraft.mcore4.lib.bson.io.Bits.readInt( _inputBuffer , _need(4) );
|
||||
}
|
||||
|
||||
public int readIntBE()
|
||||
throws IOException {
|
||||
return com.massivecraft.mcore4.lib.bson.io.Bits.readIntBE( _inputBuffer , _need(4) );
|
||||
}
|
||||
|
||||
public long readLong()
|
||||
throws IOException {
|
||||
return com.massivecraft.mcore4.lib.bson.io.Bits.readLong( _inputBuffer , _need(8) );
|
||||
}
|
||||
|
||||
public double readDouble()
|
||||
throws IOException {
|
||||
return Double.longBitsToDouble( readLong() );
|
||||
}
|
||||
|
||||
public byte read()
|
||||
throws IOException {
|
||||
if ( _pos < _len ){
|
||||
++_read;
|
||||
return _inputBuffer[_pos++];
|
||||
}
|
||||
return _inputBuffer[_need(1)];
|
||||
}
|
||||
|
||||
public void fill( byte b[] )
|
||||
throws IOException {
|
||||
fill( b , b.length );
|
||||
}
|
||||
|
||||
public void fill( byte b[] , int len )
|
||||
throws IOException {
|
||||
// first use what we have
|
||||
final int have = _len - _pos;
|
||||
final int tocopy = Math.min( len , have );
|
||||
System.arraycopy( _inputBuffer , _pos , b , 0 , tocopy );
|
||||
|
||||
_pos += tocopy;
|
||||
_read += tocopy;
|
||||
|
||||
len -= tocopy;
|
||||
|
||||
int off = tocopy;
|
||||
while ( len > 0 ){
|
||||
final int x = _raw.read( b , off , len );
|
||||
if (x <= 0)
|
||||
throw new IOException( "unexpected EOF" );
|
||||
_read += x;
|
||||
off += x;
|
||||
len -= x;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean _isAscii( byte b ){
|
||||
return b >=0 && b <= 127;
|
||||
}
|
||||
|
||||
public String readCStr() throws IOException {
|
||||
|
||||
boolean isAscii = true;
|
||||
|
||||
// short circuit 1 byte strings
|
||||
_random[0] = read();
|
||||
if (_random[0] == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
_random[1] = read();
|
||||
if (_random[1] == 0) {
|
||||
final String out = ONE_BYTE_STRINGS[_random[0]];
|
||||
return (out != null) ? out : new String(_random, 0, 1, DEFAULT_ENCODING);
|
||||
}
|
||||
|
||||
_stringBuffer.reset();
|
||||
_stringBuffer.write(_random, 0, 2);
|
||||
|
||||
isAscii = _isAscii(_random[0]) && _isAscii(_random[1]);
|
||||
|
||||
byte b;
|
||||
while ((b = read()) != 0) {
|
||||
_stringBuffer.write( b );
|
||||
isAscii = isAscii && _isAscii( b );
|
||||
}
|
||||
|
||||
String out = null;
|
||||
if ( isAscii ){
|
||||
out = _stringBuffer.asAscii();
|
||||
}
|
||||
else {
|
||||
try {
|
||||
out = _stringBuffer.asString( DEFAULT_ENCODING );
|
||||
}
|
||||
catch ( UnsupportedOperationException e ){
|
||||
throw new BSONException( "impossible" , e );
|
||||
}
|
||||
}
|
||||
_stringBuffer.reset();
|
||||
return out;
|
||||
}
|
||||
|
||||
public String readUTF8String()
|
||||
throws IOException {
|
||||
final int size = readInt();
|
||||
// this is just protection in case it's corrupted, to avoid huge strings
|
||||
if ( size <= 0 || size > MAX_STRING )
|
||||
throw new BSONException( "bad string size: " + size );
|
||||
|
||||
if ( size < _inputBuffer.length / 2 ){
|
||||
if ( size == 1 ){
|
||||
read();
|
||||
return "";
|
||||
}
|
||||
|
||||
return new String( _inputBuffer , _need(size) , size - 1 , DEFAULT_ENCODING );
|
||||
}
|
||||
|
||||
final byte [] b = size < _random.length ? _random : new byte[size];
|
||||
|
||||
fill( b , size );
|
||||
|
||||
try {
|
||||
return new String( b , 0 , size - 1 , DEFAULT_ENCODING );
|
||||
}
|
||||
catch ( java.io.UnsupportedEncodingException uee ){
|
||||
throw new BSONException( "impossible" , uee );
|
||||
}
|
||||
}
|
||||
|
||||
public int numRead() {
|
||||
return _read;
|
||||
}
|
||||
|
||||
public int getPos() {
|
||||
return _pos;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return _max;
|
||||
}
|
||||
|
||||
public void setMax(int _max) {
|
||||
this._max = _max;
|
||||
}
|
||||
|
||||
int _read;
|
||||
final InputStream _raw;
|
||||
|
||||
int _max = 4; // max number of total bytes allowed to ready
|
||||
|
||||
}
|
||||
|
||||
protected BSONInput _in;
|
||||
protected BSONCallback _callback;
|
||||
|
||||
private byte [] _random = new byte[1024]; // has to be used within a single function
|
||||
private byte [] _inputBuffer = new byte[1024];
|
||||
|
||||
private PoolOutputBuffer _stringBuffer = new PoolOutputBuffer();
|
||||
|
||||
protected int _pos; // current offset into _inputBuffer
|
||||
protected int _len; // length of valid data in _inputBuffer
|
||||
|
||||
private static final int MAX_STRING = ( 32 * 1024 * 1024 );
|
||||
|
||||
private static final String DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final boolean _isAscii( final byte b ){
|
||||
return b >=0 && b <= 127;
|
||||
}
|
||||
|
||||
static final String[] ONE_BYTE_STRINGS = new String[128];
|
||||
static void _fillRange( byte min, byte max ){
|
||||
while ( min < max ){
|
||||
String s = "";
|
||||
s += (char)min;
|
||||
ONE_BYTE_STRINGS[(int)min] = s;
|
||||
min++;
|
||||
}
|
||||
}
|
||||
static {
|
||||
_fillRange( (byte)'0' , (byte)'9' );
|
||||
_fillRange( (byte)'a' , (byte)'z' );
|
||||
_fillRange( (byte)'A' , (byte)'Z' );
|
||||
}
|
||||
}
|
||||
530
src/com/massivecraft/mcore4/lib/bson/BasicBSONEncoder.java
Normal file
530
src/com/massivecraft/mcore4/lib/bson/BasicBSONEncoder.java
Normal file
@@ -0,0 +1,530 @@
|
||||
// BSONEncoder.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.ARRAY;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.BINARY;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.BOOLEAN;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.B_BINARY;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.B_GENERAL;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.B_UUID;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.CODE;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.CODE_W_SCOPE;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.DATE;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.EOO;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.MAXKEY;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.MINKEY;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.NULL;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.NUMBER;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.NUMBER_INT;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.NUMBER_LONG;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.OBJECT;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.OID;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.REGEX;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.STRING;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.SYMBOL;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.TIMESTAMP;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.UNDEFINED;
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.regexFlags;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.Buffer;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.BasicOutputBuffer;
|
||||
import com.massivecraft.mcore4.lib.bson.io.OutputBuffer;
|
||||
import com.massivecraft.mcore4.lib.bson.types.BSONTimestamp;
|
||||
import com.massivecraft.mcore4.lib.bson.types.Binary;
|
||||
import com.massivecraft.mcore4.lib.bson.types.Code;
|
||||
import com.massivecraft.mcore4.lib.bson.types.CodeWScope;
|
||||
import com.massivecraft.mcore4.lib.bson.types.MaxKey;
|
||||
import com.massivecraft.mcore4.lib.bson.types.MinKey;
|
||||
import com.massivecraft.mcore4.lib.bson.types.ObjectId;
|
||||
import com.massivecraft.mcore4.lib.bson.types.Symbol;
|
||||
import com.massivecraft.mcore4.lib.mongodb.DBRefBase;
|
||||
|
||||
/**
|
||||
* this is meant to be pooled or cached
|
||||
* there is some per instance memory for string conversion, etc...
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BasicBSONEncoder implements BSONEncoder {
|
||||
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
public BasicBSONEncoder(){
|
||||
|
||||
}
|
||||
|
||||
public byte[] encode( BSONObject o ){
|
||||
BasicOutputBuffer buf = new BasicOutputBuffer();
|
||||
set( buf );
|
||||
putObject( o );
|
||||
done();
|
||||
return buf.toByteArray();
|
||||
}
|
||||
|
||||
public void set( OutputBuffer out ){
|
||||
if ( _buf != null )
|
||||
throw new IllegalStateException( "in the middle of something" );
|
||||
|
||||
_buf = out;
|
||||
}
|
||||
|
||||
public void done(){
|
||||
_buf = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if object was handled
|
||||
*/
|
||||
protected boolean handleSpecialObjects( String name , BSONObject o ){
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean putSpecial( String name , Object o ){
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Encodes a <code>BSONObject</code>.
|
||||
* This is for the higher level api calls
|
||||
* @param o the object to encode
|
||||
* @return the number of characters in the encoding
|
||||
*/
|
||||
public int putObject( BSONObject o ){
|
||||
return putObject( null , o );
|
||||
}
|
||||
|
||||
/**
|
||||
* this is really for embedded objects
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected int putObject( String name , BSONObject o ){
|
||||
|
||||
if ( o == null )
|
||||
throw new NullPointerException( "can't save a null object" );
|
||||
|
||||
if ( DEBUG ) System.out.println( "putObject : " + name + " [" + o.getClass() + "]" + " # keys " + o.keySet().size() );
|
||||
|
||||
final int start = _buf.getPosition();
|
||||
|
||||
byte myType = OBJECT;
|
||||
if ( o instanceof List )
|
||||
myType = ARRAY;
|
||||
|
||||
if ( handleSpecialObjects( name , o ) )
|
||||
return _buf.getPosition() - start;
|
||||
|
||||
if ( name != null ){
|
||||
_put( myType , name );
|
||||
}
|
||||
|
||||
final int sizePos = _buf.getPosition();
|
||||
_buf.writeInt( 0 ); // leaving space for this. set it at the end
|
||||
|
||||
List transientFields = null;
|
||||
boolean rewriteID = myType == OBJECT && name == null;
|
||||
|
||||
|
||||
if ( myType == OBJECT ) {
|
||||
if ( rewriteID && o.containsField( "_id" ) )
|
||||
_putObjectField( "_id" , o.get( "_id" ) );
|
||||
|
||||
{
|
||||
Object temp = o.get( "_transientFields" );
|
||||
if ( temp instanceof List )
|
||||
transientFields = (List)temp;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: reduce repeated code below.
|
||||
if ( o instanceof Map ){
|
||||
for ( Entry<String, Object> e : ((Map<String, Object>)o).entrySet() ){
|
||||
|
||||
if ( rewriteID && e.getKey().equals( "_id" ) )
|
||||
continue;
|
||||
|
||||
if ( transientFields != null && transientFields.contains( e.getKey() ) )
|
||||
continue;
|
||||
|
||||
_putObjectField( e.getKey() , e.getValue() );
|
||||
|
||||
}
|
||||
} else {
|
||||
for ( String s : o.keySet() ){
|
||||
|
||||
if ( rewriteID && s.equals( "_id" ) )
|
||||
continue;
|
||||
|
||||
if ( transientFields != null && transientFields.contains( s ) )
|
||||
continue;
|
||||
|
||||
Object val = o.get( s );
|
||||
|
||||
_putObjectField( s , val );
|
||||
|
||||
}
|
||||
}
|
||||
_buf.write( EOO );
|
||||
|
||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
||||
return _buf.getPosition() - start;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected void _putObjectField( String name , Object val ){
|
||||
|
||||
if ( name.equals( "_transientFields" ) )
|
||||
return;
|
||||
|
||||
if ( DEBUG ) System.out.println( "\t put thing : " + name );
|
||||
|
||||
if ( name.equals( "$where") && val instanceof String ){
|
||||
_put( CODE , name );
|
||||
_putValueString( val.toString() );
|
||||
return;
|
||||
}
|
||||
|
||||
val = BSON.applyEncodingHooks( val );
|
||||
|
||||
if ( val == null )
|
||||
putNull(name);
|
||||
else if ( val instanceof Date )
|
||||
putDate( name , (Date)val );
|
||||
else if ( val instanceof Number )
|
||||
putNumber(name, (Number)val );
|
||||
else if ( val instanceof Character )
|
||||
putString(name, val.toString() );
|
||||
else if ( val instanceof String )
|
||||
putString(name, val.toString() );
|
||||
else if ( val instanceof ObjectId )
|
||||
putObjectId(name, (ObjectId)val );
|
||||
else if ( val instanceof BSONObject )
|
||||
putObject(name, (BSONObject)val );
|
||||
else if ( val instanceof Boolean )
|
||||
putBoolean(name, (Boolean)val );
|
||||
else if ( val instanceof Pattern )
|
||||
putPattern(name, (Pattern)val );
|
||||
else if ( val instanceof Map )
|
||||
putMap( name , (Map)val );
|
||||
else if ( val instanceof Iterable)
|
||||
putIterable( name , (Iterable)val );
|
||||
else if ( val instanceof byte[] )
|
||||
putBinary( name , (byte[])val );
|
||||
else if ( val instanceof Binary )
|
||||
putBinary( name , (Binary)val );
|
||||
else if ( val instanceof UUID )
|
||||
putUUID( name , (UUID)val );
|
||||
else if ( val.getClass().isArray() )
|
||||
putArray( name , val );
|
||||
|
||||
else if (val instanceof Symbol) {
|
||||
putSymbol(name, (Symbol) val);
|
||||
}
|
||||
else if (val instanceof BSONTimestamp) {
|
||||
putTimestamp( name , (BSONTimestamp)val );
|
||||
}
|
||||
else if (val instanceof CodeWScope) {
|
||||
putCodeWScope( name , (CodeWScope)val );
|
||||
}
|
||||
else if (val instanceof Code) {
|
||||
putCode( name , (Code)val );
|
||||
}
|
||||
else if (val instanceof DBRefBase) {
|
||||
BSONObject temp = new BasicBSONObject();
|
||||
temp.put("$ref", ((DBRefBase)val).getRef());
|
||||
temp.put("$id", ((DBRefBase)val).getId());
|
||||
putObject( name, temp );
|
||||
}
|
||||
else if ( val instanceof MinKey )
|
||||
putMinKey( name );
|
||||
else if ( val instanceof MaxKey )
|
||||
putMaxKey( name );
|
||||
else if ( putSpecial( name , val ) ){
|
||||
// no-op
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "can't serialize " + val.getClass() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void putArray( String name , Object array ) {
|
||||
_put( ARRAY , name );
|
||||
final int sizePos = _buf.getPosition();
|
||||
_buf.writeInt( 0 );
|
||||
|
||||
int size = Array.getLength(array);
|
||||
for ( int i = 0; i < size; i++ )
|
||||
_putObjectField( String.valueOf( i ) , Array.get( array, i ) );
|
||||
|
||||
_buf.write( EOO );
|
||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void putIterable( String name , Iterable l ){
|
||||
_put( ARRAY , name );
|
||||
final int sizePos = _buf.getPosition();
|
||||
_buf.writeInt( 0 );
|
||||
|
||||
int i=0;
|
||||
for ( Object obj: l ) {
|
||||
_putObjectField( String.valueOf( i ) , obj );
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
_buf.write( EOO );
|
||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void putMap( String name , Map m ){
|
||||
_put( OBJECT , name );
|
||||
final int sizePos = _buf.getPosition();
|
||||
_buf.writeInt( 0 );
|
||||
|
||||
for ( Map.Entry entry : (Set<Map.Entry>)m.entrySet() )
|
||||
_putObjectField( entry.getKey().toString() , entry.getValue() );
|
||||
|
||||
_buf.write( EOO );
|
||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
||||
}
|
||||
|
||||
|
||||
protected void putNull( String name ){
|
||||
_put( NULL , name );
|
||||
}
|
||||
|
||||
protected void putUndefined(String name){
|
||||
_put(UNDEFINED, name);
|
||||
}
|
||||
|
||||
protected void putTimestamp(String name, BSONTimestamp ts ){
|
||||
_put( TIMESTAMP , name );
|
||||
_buf.writeInt( ts.getInc() );
|
||||
_buf.writeInt( ts.getTime() );
|
||||
}
|
||||
|
||||
protected void putCodeWScope( String name , CodeWScope code ){
|
||||
_put( CODE_W_SCOPE , name );
|
||||
int temp = _buf.getPosition();
|
||||
_buf.writeInt( 0 );
|
||||
_putValueString( code.getCode() );
|
||||
putObject( code.getScope() );
|
||||
_buf.writeInt( temp , _buf.getPosition() - temp );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected void putCode( String name , Code code ){
|
||||
_put( CODE , name );
|
||||
int temp = _buf.getPosition();
|
||||
_putValueString( code.getCode() );
|
||||
}
|
||||
|
||||
protected void putBoolean( String name , Boolean b ){
|
||||
_put( BOOLEAN , name );
|
||||
_buf.write( b ? (byte)0x1 : (byte)0x0 );
|
||||
}
|
||||
|
||||
protected void putDate( String name , Date d ){
|
||||
_put( DATE , name );
|
||||
_buf.writeLong( d.getTime() );
|
||||
}
|
||||
|
||||
protected void putNumber( String name , Number n ){
|
||||
if ( n instanceof Integer ||
|
||||
n instanceof Short ||
|
||||
n instanceof Byte ||
|
||||
n instanceof AtomicInteger ){
|
||||
_put( NUMBER_INT , name );
|
||||
_buf.writeInt( n.intValue() );
|
||||
}
|
||||
else if ( n instanceof Long || n instanceof AtomicLong ) {
|
||||
_put( NUMBER_LONG , name );
|
||||
_buf.writeLong( n.longValue() );
|
||||
}
|
||||
else if ( n instanceof Float || n instanceof Double ) {
|
||||
_put( NUMBER , name );
|
||||
_buf.writeDouble( n.doubleValue() );
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "can't serialize " + n.getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
protected void putBinary( String name , byte[] data ){
|
||||
putBinary( name, B_GENERAL, data );
|
||||
}
|
||||
|
||||
protected void putBinary( String name , Binary val ){
|
||||
putBinary( name, val.getType(), val.getData() );
|
||||
}
|
||||
|
||||
private void putBinary( String name , int type , byte[] data ){
|
||||
_put( BINARY , name );
|
||||
int totalLen = data.length;
|
||||
|
||||
if (type == B_BINARY)
|
||||
totalLen += 4;
|
||||
|
||||
_buf.writeInt( totalLen );
|
||||
_buf.write( type );
|
||||
if (type == B_BINARY)
|
||||
_buf.writeInt( totalLen -4 );
|
||||
int before = _buf.getPosition();
|
||||
_buf.write( data );
|
||||
int after = _buf.getPosition();
|
||||
com.massivecraft.mcore4.lib.mongodb.util.MyAsserts.assertEquals( after - before , data.length );
|
||||
}
|
||||
|
||||
protected void putUUID( String name , UUID val ){
|
||||
_put( BINARY , name );
|
||||
_buf.writeInt( 16 );
|
||||
_buf.write( B_UUID );
|
||||
_buf.writeLong( val.getMostSignificantBits());
|
||||
_buf.writeLong( val.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
protected void putSymbol( String name , Symbol s ){
|
||||
_putString(name, s.getSymbol(), SYMBOL);
|
||||
}
|
||||
|
||||
protected void putString(String name, String s) {
|
||||
_putString(name, s, STRING);
|
||||
}
|
||||
|
||||
private void _putString( String name , String s, byte type ){
|
||||
_put( type , name );
|
||||
_putValueString( s );
|
||||
}
|
||||
|
||||
protected void putObjectId( String name , ObjectId oid ){
|
||||
_put( OID , name );
|
||||
// according to spec, values should be stored big endian
|
||||
_buf.writeIntBE( oid._time() );
|
||||
_buf.writeIntBE( oid._machine() );
|
||||
_buf.writeIntBE( oid._inc() );
|
||||
}
|
||||
|
||||
private void putPattern( String name, Pattern p ) {
|
||||
_put( REGEX , name );
|
||||
_put( p.pattern() );
|
||||
_put( regexFlags( p.flags() ) );
|
||||
}
|
||||
|
||||
private void putMinKey( String name ) {
|
||||
_put( MINKEY , name );
|
||||
}
|
||||
|
||||
private void putMaxKey( String name ) {
|
||||
_put( MAXKEY , name );
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
/**
|
||||
* Encodes the type and key.
|
||||
*
|
||||
*/
|
||||
protected void _put( byte type , String name ){
|
||||
_buf.write( type );
|
||||
_put( name );
|
||||
}
|
||||
|
||||
protected void _putValueString( String s ){
|
||||
int lenPos = _buf.getPosition();
|
||||
_buf.writeInt( 0 ); // making space for size
|
||||
int strLen = _put( s );
|
||||
_buf.writeInt( lenPos , strLen );
|
||||
}
|
||||
|
||||
void _reset( Buffer b ){
|
||||
b.position(0);
|
||||
b.limit( b.capacity() );
|
||||
}
|
||||
|
||||
/**
|
||||
* puts as utf-8 string
|
||||
*/
|
||||
protected int _put( String str ){
|
||||
|
||||
final int len = str.length();
|
||||
int total = 0;
|
||||
|
||||
for ( int i=0; i<len; ){
|
||||
int c = Character.codePointAt( str , i );
|
||||
|
||||
if ( c < 0x80 ){
|
||||
_buf.write( (byte)c );
|
||||
total += 1;
|
||||
}
|
||||
else if ( c < 0x800 ){
|
||||
_buf.write( (byte)(0xc0 + (c >> 6) ) );
|
||||
_buf.write( (byte)(0x80 + (c & 0x3f) ) );
|
||||
total += 2;
|
||||
}
|
||||
else if (c < 0x10000){
|
||||
_buf.write( (byte)(0xe0 + (c >> 12) ) );
|
||||
_buf.write( (byte)(0x80 + ((c >> 6) & 0x3f) ) );
|
||||
_buf.write( (byte)(0x80 + (c & 0x3f) ) );
|
||||
total += 3;
|
||||
}
|
||||
else {
|
||||
_buf.write( (byte)(0xf0 + (c >> 18)) );
|
||||
_buf.write( (byte)(0x80 + ((c >> 12) & 0x3f)) );
|
||||
_buf.write( (byte)(0x80 + ((c >> 6) & 0x3f)) );
|
||||
_buf.write( (byte)(0x80 + (c & 0x3f)) );
|
||||
total += 4;
|
||||
}
|
||||
|
||||
i += Character.charCount(c);
|
||||
}
|
||||
|
||||
_buf.write( (byte)0 );
|
||||
total++;
|
||||
return total;
|
||||
}
|
||||
|
||||
public void writeInt( int x ){
|
||||
_buf.writeInt( x );
|
||||
}
|
||||
|
||||
public void writeLong( long x ){
|
||||
_buf.writeLong( x );
|
||||
}
|
||||
|
||||
public void writeCString( String s ){
|
||||
_put( s );
|
||||
}
|
||||
|
||||
protected OutputBuffer _buf;
|
||||
|
||||
}
|
||||
355
src/com/massivecraft/mcore4/lib/bson/BasicBSONObject.java
Normal file
355
src/com/massivecraft/mcore4/lib/bson/BasicBSONObject.java
Normal file
@@ -0,0 +1,355 @@
|
||||
// BasicBSONObject.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
// BSON
|
||||
import com.massivecraft.mcore4.lib.bson.types.ObjectId;
|
||||
|
||||
// Java
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A simple implementation of <code>DBObject</code>.
|
||||
* A <code>DBObject</code> can be created as follows, using this class:
|
||||
* <blockquote><pre>
|
||||
* DBObject obj = new BasicBSONObject();
|
||||
* obj.put( "foo", "bar" );
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
public class BasicBSONObject extends LinkedHashMap<String,Object> implements BSONObject {
|
||||
|
||||
private static final long serialVersionUID = -4415279469780082174L;
|
||||
|
||||
/**
|
||||
* Creates an empty object.
|
||||
*/
|
||||
public BasicBSONObject(){
|
||||
}
|
||||
|
||||
public BasicBSONObject(int size){
|
||||
super(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience CTOR
|
||||
* @param key key under which to store
|
||||
* @param value value to stor
|
||||
*/
|
||||
public BasicBSONObject(String key, Object value){
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DBObject from a map.
|
||||
* @param m map to convert
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public BasicBSONObject(Map m) {
|
||||
super(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a DBObject to a map.
|
||||
* @return the DBObject
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Map toMap() {
|
||||
return new LinkedHashMap<String,Object>(this);
|
||||
}
|
||||
|
||||
/** Deletes a field from this object.
|
||||
* @param key the field name to remove
|
||||
* @return the object removed
|
||||
*/
|
||||
public Object removeField( String key ){
|
||||
return remove( key );
|
||||
}
|
||||
|
||||
/** Checks if this object contains a given field
|
||||
* @param field field name
|
||||
* @return if the field exists
|
||||
*/
|
||||
public boolean containsField( String field ){
|
||||
return super.containsKey(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean containsKey( String key ){
|
||||
return containsField(key);
|
||||
}
|
||||
|
||||
/** Gets a value from this object
|
||||
* @param key field name
|
||||
* @return the value
|
||||
*/
|
||||
public Object get( String key ){
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
/** Returns the value of a field as an <code>int</code>.
|
||||
* @param key the field to look for
|
||||
* @return the field value (or default)
|
||||
*/
|
||||
public int getInt( String key ){
|
||||
Object o = get(key);
|
||||
if ( o == null )
|
||||
throw new NullPointerException( "no value for: " + key );
|
||||
|
||||
return BSON.toInt( o );
|
||||
}
|
||||
|
||||
/** Returns the value of a field as an <code>int</code>.
|
||||
* @param key the field to look for
|
||||
* @param def the default to return
|
||||
* @return the field value (or default)
|
||||
*/
|
||||
public int getInt( String key , int def ){
|
||||
Object foo = get( key );
|
||||
if ( foo == null )
|
||||
return def;
|
||||
|
||||
return BSON.toInt( foo );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field as a <code>long</code>.
|
||||
*
|
||||
* @param key the field to return
|
||||
* @return the field value
|
||||
*/
|
||||
public long getLong( String key){
|
||||
Object foo = get( key );
|
||||
return ((Number)foo).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field as an <code>long</code>.
|
||||
* @param key the field to look for
|
||||
* @param def the default to return
|
||||
* @return the field value (or default)
|
||||
*/
|
||||
public long getLong( String key , long def ) {
|
||||
Object foo = get( key );
|
||||
if ( foo == null )
|
||||
return def;
|
||||
|
||||
return ((Number)foo).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field as a <code>double</code>.
|
||||
*
|
||||
* @param key the field to return
|
||||
* @return the field value
|
||||
*/
|
||||
public double getDouble( String key){
|
||||
Object foo = get( key );
|
||||
return ((Number)foo).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field as an <code>double</code>.
|
||||
* @param key the field to look for
|
||||
* @param def the default to return
|
||||
* @return the field value (or default)
|
||||
*/
|
||||
public double getDouble( String key , double def ) {
|
||||
Object foo = get( key );
|
||||
if ( foo == null )
|
||||
return def;
|
||||
|
||||
return ((Number)foo).doubleValue();
|
||||
}
|
||||
|
||||
/** Returns the value of a field as a string
|
||||
* @param key the field to look up
|
||||
* @return the value of the field, converted to a string
|
||||
*/
|
||||
public String getString( String key ){
|
||||
Object foo = get( key );
|
||||
if ( foo == null )
|
||||
return null;
|
||||
return foo.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field as a string
|
||||
* @param key the field to look up
|
||||
* @param def the default to return
|
||||
* @return the value of the field, converted to a string
|
||||
*/
|
||||
public String getString( String key, final String def ) {
|
||||
Object foo = get( key );
|
||||
if ( foo == null )
|
||||
return def;
|
||||
|
||||
return foo.toString();
|
||||
}
|
||||
|
||||
/** Returns the value of a field as a boolean.
|
||||
* @param key the field to look up
|
||||
* @return the value of the field, or false if field does not exist
|
||||
*/
|
||||
public boolean getBoolean( String key ){
|
||||
return getBoolean(key, false);
|
||||
}
|
||||
|
||||
/** Returns the value of a field as a boolean
|
||||
* @param key the field to look up
|
||||
* @param def the default value in case the field is not found
|
||||
* @return the value of the field, converted to a string
|
||||
*/
|
||||
public boolean getBoolean( String key , boolean def ){
|
||||
Object foo = get( key );
|
||||
if ( foo == null )
|
||||
return def;
|
||||
if ( foo instanceof Number )
|
||||
return ((Number)foo).intValue() > 0;
|
||||
if ( foo instanceof Boolean )
|
||||
return ((Boolean)foo).booleanValue();
|
||||
throw new IllegalArgumentException( "can't coerce to bool:" + foo.getClass() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object id or null if not set.
|
||||
* @param field The field to return
|
||||
* @return The field object value or null if not found (or if null :-^).
|
||||
*/
|
||||
public ObjectId getObjectId( final String field ) {
|
||||
return (ObjectId) get( field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object id or def if not set.
|
||||
* @param field The field to return
|
||||
* @param def the default value in case the field is not found
|
||||
* @return The field object value or def if not set.
|
||||
*/
|
||||
public ObjectId getObjectId( final String field, final ObjectId def ) {
|
||||
final Object foo = get( field );
|
||||
return (foo != null) ? (ObjectId)foo : def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date or null if not set.
|
||||
* @param field The field to return
|
||||
* @return The field object value or null if not found.
|
||||
*/
|
||||
public Date getDate( final String field ) {
|
||||
return (Date) get( field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date or def if not set.
|
||||
* @param field The field to return
|
||||
* @param def the default value in case the field is not found
|
||||
* @return The field object value or def if not set.
|
||||
*/
|
||||
public Date getDate( final String field, final Date def ) {
|
||||
final Object foo = get( field );
|
||||
return (foo != null) ? (Date)foo : def;
|
||||
}
|
||||
|
||||
/** Add a key/value pair to this object
|
||||
* @param key the field name
|
||||
* @param val the field value
|
||||
* @return the <code>val</code> parameter
|
||||
*/
|
||||
public Object put( String key , Object val ){
|
||||
return super.put( key , val );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void putAll( Map m ){
|
||||
for ( Map.Entry entry : (Set<Map.Entry>)m.entrySet() ){
|
||||
put( entry.getKey().toString() , entry.getValue() );
|
||||
}
|
||||
}
|
||||
|
||||
public void putAll( BSONObject o ){
|
||||
for ( String k : o.keySet() ){
|
||||
put( k , o.get( k ) );
|
||||
}
|
||||
}
|
||||
|
||||
/** Add a key/value pair to this object
|
||||
* @param key the field name
|
||||
* @param val the field value
|
||||
* @return <code>this</code>
|
||||
*/
|
||||
public BasicBSONObject append( String key , Object val ){
|
||||
put( key , val );
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns a JSON serialization of this object
|
||||
* @return JSON serialization
|
||||
*/
|
||||
public String toString(){
|
||||
return com.massivecraft.mcore4.lib.mongodb.util.JSON.serialize( this );
|
||||
}
|
||||
|
||||
public boolean equals( Object o ){
|
||||
if ( ! ( o instanceof BSONObject ) )
|
||||
return false;
|
||||
|
||||
BSONObject other = (BSONObject)o;
|
||||
if ( ! keySet().equals( other.keySet() ) )
|
||||
return false;
|
||||
|
||||
for ( String key : keySet() ){
|
||||
Object a = get( key );
|
||||
Object b = other.get( key );
|
||||
|
||||
if ( a == null ){
|
||||
if ( b != null )
|
||||
return false;
|
||||
}
|
||||
if ( b == null ){
|
||||
if ( a != null )
|
||||
return false;
|
||||
}
|
||||
else if ( a instanceof Number && b instanceof Number ){
|
||||
if ( ((Number)a).doubleValue() !=
|
||||
((Number)b).doubleValue() )
|
||||
return false;
|
||||
}
|
||||
else if ( a instanceof Pattern && b instanceof Pattern ){
|
||||
Pattern p1 = (Pattern) a;
|
||||
Pattern p2 = (Pattern) b;
|
||||
if (!p1.pattern().equals(p2.pattern()) || p1.flags() != p2.flags())
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if ( ! a.equals( b ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
143
src/com/massivecraft/mcore4/lib/bson/EmptyBSONCallback.java
Normal file
143
src/com/massivecraft/mcore4/lib/bson/EmptyBSONCallback.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Copyright (C) 2011 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.types.ObjectId;
|
||||
|
||||
public class EmptyBSONCallback implements BSONCallback {
|
||||
|
||||
public void objectStart(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void objectStart( String name ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void objectStart( boolean array ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public Object objectDone(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public BSONCallback createBSONCallback(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void arrayStart(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void arrayStart( String name ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public Object arrayDone(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotNull( String name ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotUndefined( String name ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotMinKey( String name ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotMaxKey( String name ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotBoolean( String name , boolean v ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotDouble( String name , double v ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotInt( String name , int v ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotLong( String name , long v ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotDate( String name , long millis ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotString( String name , String v ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotSymbol( String name , String v ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotRegex( String name , String pattern , String flags ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotTimestamp( String name , int time , int inc ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotObjectId( String name , ObjectId id ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotDBRef( String name , String ns , ObjectId id ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void gotBinaryArray( String name , byte[] data ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotUUID( String name , long part1 , long part2 ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotCode( String name , String code ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotCodeWScope( String name , String code , Object scope ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public Object get(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void gotBinary( String name , byte type , byte[] data ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (C) 2011 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.BSONByteBuffer;
|
||||
|
||||
/**
|
||||
* @author brendan
|
||||
* @author scotthernandez
|
||||
*/
|
||||
public class KeyCachingLazyBSONObject extends LazyBSONObject {
|
||||
|
||||
public KeyCachingLazyBSONObject(byte[] data , LazyBSONCallback cbk) { super( data , cbk ); }
|
||||
public KeyCachingLazyBSONObject(byte[] data , int offset , LazyBSONCallback cbk) { super( data , offset , cbk ); }
|
||||
public KeyCachingLazyBSONObject( BSONByteBuffer buffer, LazyBSONCallback callback ){ super( buffer, callback ); }
|
||||
public KeyCachingLazyBSONObject( BSONByteBuffer buffer, int offset, LazyBSONCallback callback ){ super( buffer, offset, callback ); }
|
||||
|
||||
@Override
|
||||
public Object get( String key ) {
|
||||
ensureFieldList();
|
||||
return super.get( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsField( String s ) {
|
||||
ensureFieldList();
|
||||
if (! fieldIndex.containsKey( s ) )
|
||||
return false;
|
||||
else
|
||||
return super.containsField( s );
|
||||
}
|
||||
|
||||
synchronized private void ensureFieldList() {
|
||||
//only run once
|
||||
if (fieldIndex == null) return;
|
||||
try {
|
||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
||||
|
||||
while ( !isElementEmpty( offset ) ){
|
||||
int fieldSize = sizeCString( offset );
|
||||
int elementSize = getElementBSONSize( offset++ );
|
||||
String name = _input.getCString( offset );
|
||||
ElementRecord _t_record = new ElementRecord( name, offset );
|
||||
fieldIndex.put( name, _t_record );
|
||||
offset += ( fieldSize + elementSize );
|
||||
}
|
||||
} catch (Exception e) {
|
||||
fieldIndex = new HashMap<String, ElementRecord>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private HashMap<String, ElementRecord> fieldIndex = new HashMap<String, ElementRecord>();
|
||||
|
||||
}
|
||||
88
src/com/massivecraft/mcore4/lib/bson/LazyBSONCallback.java
Normal file
88
src/com/massivecraft/mcore4/lib/bson/LazyBSONCallback.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.types.ObjectId;
|
||||
import com.massivecraft.mcore4.lib.mongodb.LazyDBObject;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LazyBSONCallback extends EmptyBSONCallback {
|
||||
|
||||
public void objectStart(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void objectStart( String name ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void objectStart( boolean array ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public Object objectDone(){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
_root = null;
|
||||
}
|
||||
|
||||
public Object get(){
|
||||
return _root;
|
||||
}
|
||||
|
||||
public void gotBinary( String name, byte type, byte[] data ){
|
||||
setRootObject( createObject( data, 0 ) );
|
||||
}
|
||||
|
||||
public void setRootObject( Object root ){
|
||||
_root = root;
|
||||
}
|
||||
|
||||
public Object createObject( byte[] data, int offset ){
|
||||
return new LazyDBObject( data, offset, this );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List createArray( byte[] data, int offset ){
|
||||
return new LazyDBList( data, offset, this );
|
||||
}
|
||||
|
||||
public Object createDBRef( String ns, ObjectId id ){
|
||||
return new BasicBSONObject( "$ns", ns ).append( "$id", id );
|
||||
}
|
||||
|
||||
|
||||
/* public Object createObject(InputStream input, int offset) {
|
||||
try {
|
||||
return new LazyBSONObject(input, offset, this);
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}*/
|
||||
private Object _root;
|
||||
@SuppressWarnings("unused")
|
||||
private static final Logger log = Logger.getLogger( "org.bson.LazyBSONCallback" );
|
||||
}
|
||||
70
src/com/massivecraft/mcore4/lib/bson/LazyBSONDecoder.java
Normal file
70
src/com/massivecraft/mcore4/lib/bson/LazyBSONDecoder.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.Bits;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* implementation of BSONDecoder that creates LazyBSONObject instances
|
||||
*/
|
||||
public class LazyBSONDecoder implements BSONDecoder {
|
||||
static final Logger LOG = Logger.getLogger( LazyBSONDecoder.class.getName() );
|
||||
|
||||
public BSONObject readObject(byte[] b) {
|
||||
try {
|
||||
return readObject( new ByteArrayInputStream( b ) );
|
||||
}
|
||||
catch ( IOException ioe ){
|
||||
throw new BSONException( "should be impossible" , ioe );
|
||||
}
|
||||
}
|
||||
|
||||
public BSONObject readObject(InputStream in) throws IOException {
|
||||
BSONCallback c = new LazyBSONCallback();
|
||||
decode( in , c );
|
||||
return (BSONObject)c.get();
|
||||
}
|
||||
|
||||
public int decode(byte[] b, BSONCallback callback) {
|
||||
try {
|
||||
return decode( new ByteArrayInputStream( b ), callback );
|
||||
}
|
||||
catch ( IOException ioe ) {
|
||||
throw new BSONException( "should be impossible" , ioe );
|
||||
}
|
||||
}
|
||||
|
||||
public int decode(InputStream in, BSONCallback callback) throws IOException {
|
||||
byte[] objSizeBuffer = new byte[BYTES_IN_INTEGER];
|
||||
Bits.readFully(in, objSizeBuffer, 0, BYTES_IN_INTEGER);
|
||||
int objSize = Bits.readInt(objSizeBuffer);
|
||||
byte[] data = new byte[objSize];
|
||||
System.arraycopy(objSizeBuffer, 0, data, 0, BYTES_IN_INTEGER);
|
||||
|
||||
Bits.readFully(in, data, BYTES_IN_INTEGER, objSize - BYTES_IN_INTEGER);
|
||||
|
||||
// note that we are handing off ownership of the data byte array to the callback
|
||||
callback.gotBinary(null, (byte) 0, data);
|
||||
return objSize;
|
||||
}
|
||||
|
||||
private static int BYTES_IN_INTEGER = 4;
|
||||
}
|
||||
177
src/com/massivecraft/mcore4/lib/bson/LazyBSONList.java
Normal file
177
src/com/massivecraft/mcore4/lib/bson/LazyBSONList.java
Normal file
@@ -0,0 +1,177 @@
|
||||
package com.massivecraft.mcore4.lib.bson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.BSONByteBuffer;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings( "rawtypes" )
|
||||
public class LazyBSONList extends LazyBSONObject implements List {
|
||||
|
||||
public LazyBSONList(byte[] data , LazyBSONCallback callback) { super( data , callback ); }
|
||||
public LazyBSONList(byte[] data , int offset , LazyBSONCallback callback) { super( data , offset , callback ); }
|
||||
public LazyBSONList(BSONByteBuffer buffer , LazyBSONCallback callback) { super( buffer , callback ); }
|
||||
public LazyBSONList(BSONByteBuffer buffer , int offset , LazyBSONCallback callback) { super( buffer , offset , callback ); }
|
||||
|
||||
@Override
|
||||
public boolean contains( Object arg0 ){
|
||||
return indexOf(arg0) > -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll( Collection arg0 ){
|
||||
for ( Object obj : arg0 ) {
|
||||
if ( !contains( obj ) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get( int pos ){
|
||||
return get("" + pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator iterator(){
|
||||
return new LazyBSONListIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf( Object arg0 ){
|
||||
int pos = 0;
|
||||
Iterator it = iterator();
|
||||
while ( it.hasNext() ) {
|
||||
Object curr = it.next();
|
||||
if ( arg0.equals( curr ) )
|
||||
return pos;
|
||||
|
||||
pos++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf( Object arg0 ){
|
||||
int pos = 0;
|
||||
int lastFound = -1;
|
||||
|
||||
Iterator it = iterator();
|
||||
while(it.hasNext()) {
|
||||
Object curr = it.next();
|
||||
if(arg0.equals( curr ))
|
||||
lastFound = pos;
|
||||
|
||||
pos++;
|
||||
}
|
||||
|
||||
return lastFound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size(){
|
||||
//TODO check the last one and get the key/field name to see the ordinal position in case the array is stored with missing elements.
|
||||
return getElements().size();
|
||||
}
|
||||
|
||||
public class LazyBSONListIterator implements Iterator {
|
||||
List<ElementRecord> elements;
|
||||
int pos=0;
|
||||
|
||||
public LazyBSONListIterator() {
|
||||
elements = getElements();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext(){
|
||||
return pos < elements.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object next(){
|
||||
return getElementValue(elements.get(pos++));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator( int arg0 ){
|
||||
throw new UnsupportedOperationException( "Not Supported" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator(){
|
||||
throw new UnsupportedOperationException( "Not Supported" );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean add( Object arg0 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( int arg0 , Object arg1 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll( Collection arg0 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll( int arg0 , Collection arg1 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove( Object arg0 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove( int arg0 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll( Collection arg0 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll( Collection arg0 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object set( int arg0 , Object arg1 ){
|
||||
throw new UnsupportedOperationException( "Read Only" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List subList( int arg0 , int arg1 ){
|
||||
throw new UnsupportedOperationException( "Not Supported" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray(){
|
||||
throw new UnsupportedOperationException( "Not Supported" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray( Object[] arg0 ){
|
||||
throw new UnsupportedOperationException( "Not Supported" );
|
||||
}
|
||||
|
||||
}
|
||||
691
src/com/massivecraft/mcore4/lib/bson/LazyBSONObject.java
Normal file
691
src/com/massivecraft/mcore4/lib/bson/LazyBSONObject.java
Normal file
@@ -0,0 +1,691 @@
|
||||
/**
|
||||
* Copyright (C) 2008-2011 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.BSONByteBuffer;
|
||||
import com.massivecraft.mcore4.lib.bson.types.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author antoine
|
||||
* @author brendan
|
||||
* @author scotthernandez
|
||||
* @author Kilroy Wuz Here
|
||||
*/
|
||||
public class LazyBSONObject implements BSONObject {
|
||||
|
||||
public LazyBSONObject( byte[] data, LazyBSONCallback callback ){
|
||||
this( BSONByteBuffer.wrap( data ), callback );
|
||||
}
|
||||
|
||||
public LazyBSONObject( byte[] data, int offset, LazyBSONCallback callback ){
|
||||
this( BSONByteBuffer.wrap( data, offset, data.length - offset ), offset, callback );
|
||||
}
|
||||
|
||||
public LazyBSONObject( BSONByteBuffer buffer, LazyBSONCallback callback ){
|
||||
this( buffer, 0, callback );
|
||||
}
|
||||
|
||||
public LazyBSONObject( BSONByteBuffer buffer, int offset, LazyBSONCallback callback ){
|
||||
_callback = callback;
|
||||
_input = buffer;
|
||||
_doc_start_offset = offset;
|
||||
}
|
||||
|
||||
|
||||
class ElementRecord {
|
||||
ElementRecord( final String name, final int offset ){
|
||||
this.name = name;
|
||||
this.offset = offset;
|
||||
this.type = getElementType( offset - 1 );
|
||||
this.fieldNameSize = sizeCString( offset );
|
||||
this.valueOffset = offset + fieldNameSize;
|
||||
}
|
||||
|
||||
final String name;
|
||||
/**
|
||||
* The offset the record begins at.
|
||||
*/
|
||||
final byte type;
|
||||
final int fieldNameSize;
|
||||
final int valueOffset;
|
||||
final int offset;
|
||||
}
|
||||
|
||||
class LazyBSONKeyIterator implements Iterator<String> {
|
||||
|
||||
public boolean hasNext(){
|
||||
return !isElementEmpty( offset );
|
||||
}
|
||||
|
||||
public String next(){
|
||||
int fieldSize = sizeCString( offset + 1);
|
||||
int elementSize = getElementBSONSize( offset );
|
||||
String key = _input.getCString( offset + 1);
|
||||
offset += fieldSize + elementSize + 1;
|
||||
return key;
|
||||
}
|
||||
|
||||
public void remove(){
|
||||
throw new UnsupportedOperationException( "Read only" );
|
||||
}
|
||||
|
||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
||||
}
|
||||
|
||||
public class LazyBSONKeySet extends ReadOnlySet<String> {
|
||||
|
||||
/**
|
||||
* This method runs in time linear to the total size of all keys in the document.
|
||||
*
|
||||
* @return the number of keys in the document
|
||||
*/
|
||||
@Override
|
||||
public int size(){
|
||||
int size = 0;
|
||||
Iterator<String> iter = iterator();
|
||||
while(iter.hasNext()) {
|
||||
iter.next();
|
||||
++size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty(){
|
||||
return LazyBSONObject.this.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains( Object o ){
|
||||
for ( String key : this ){
|
||||
if ( key.equals( o ) ){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator(){
|
||||
return new LazyBSONKeyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] toArray(){
|
||||
String[] a = new String[size()];
|
||||
return toArray(a);
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
int size = size();
|
||||
|
||||
T[] localArray = a.length >= size ? a :
|
||||
(T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
|
||||
|
||||
int i = 0;
|
||||
for ( String key : this ){
|
||||
localArray[i++] = (T) key;
|
||||
}
|
||||
|
||||
if (localArray.length > i) {
|
||||
localArray[i] = null;
|
||||
}
|
||||
return localArray;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add( String e ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove( Object o ){
|
||||
throw new UnsupportedOperationException( "Not supported yet." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll( Collection<?> collection ){
|
||||
for ( Object item : collection ){
|
||||
if ( !contains( item ) ){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class LazyBSONEntryIterator implements Iterator<Map.Entry<String, Object>> {
|
||||
|
||||
public boolean hasNext(){
|
||||
return !isElementEmpty( offset );
|
||||
}
|
||||
|
||||
public Map.Entry<String, Object> next(){
|
||||
int fieldSize = sizeCString(offset + 1);
|
||||
int elementSize = getElementBSONSize(offset);
|
||||
String key = _input.getCString(offset + 1);
|
||||
final ElementRecord nextElementRecord = new ElementRecord(key, ++offset);
|
||||
offset += fieldSize + elementSize;
|
||||
return new Map.Entry<String, Object>() {
|
||||
@Override
|
||||
public String getKey() {
|
||||
return nextElementRecord.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return getElementValue(nextElementRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(Object value) {
|
||||
throw new UnsupportedOperationException("Read only");
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Map.Entry))
|
||||
return false;
|
||||
Map.Entry e = (Map.Entry) o;
|
||||
return getKey().equals(e.getKey()) && getValue().equals(e.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getKey().hashCode() ^ getValue().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getKey() + "=" + getValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void remove(){
|
||||
throw new UnsupportedOperationException( "Read only" );
|
||||
}
|
||||
|
||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
||||
}
|
||||
|
||||
class LazyBSONEntrySet extends ReadOnlySet<Map.Entry<String, Object>> {
|
||||
@Override
|
||||
public int size() {
|
||||
return LazyBSONObject.this.keySet().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return LazyBSONObject.this.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
Iterator<Map.Entry<String, Object>> iter = iterator();
|
||||
while (iter.hasNext()) {
|
||||
if (iter.next().equals(o)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
for (Object cur : c) {
|
||||
if (!contains(cur)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, Object>> iterator() {
|
||||
return new LazyBSONEntryIterator();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
Map.Entry[] array = new Map.Entry[size()];
|
||||
return toArray(array);
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
int size = size();
|
||||
|
||||
T[] localArray = a.length >= size ? a :
|
||||
(T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
|
||||
|
||||
Iterator<Map.Entry<String, Object>> iter = iterator();
|
||||
int i = 0;
|
||||
while(iter.hasNext()) {
|
||||
localArray[i++] = (T) iter.next();
|
||||
}
|
||||
|
||||
if (localArray.length > i) {
|
||||
localArray[i] = null;
|
||||
}
|
||||
|
||||
return localArray;
|
||||
}
|
||||
}
|
||||
|
||||
// Base class that throws UnsupportedOperationException for any method that writes to the Set
|
||||
abstract class ReadOnlySet<E> implements Set<E> {
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
throw new UnsupportedOperationException("Read-only Set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException("Read-only Set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
throw new UnsupportedOperationException("Read-only Set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException("Read-only Set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException("Read-only Set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException("Read-only Set");
|
||||
}
|
||||
}
|
||||
|
||||
public Object put( String key, Object v ){
|
||||
throw new UnsupportedOperationException( "Object is read only" );
|
||||
}
|
||||
|
||||
public void putAll( BSONObject o ){
|
||||
throw new UnsupportedOperationException( "Object is read only" );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void putAll( Map m ){
|
||||
throw new UnsupportedOperationException( "Object is read only" );
|
||||
}
|
||||
|
||||
public Object get( String key ){
|
||||
//get element up to the key
|
||||
ElementRecord element = getElement(key);
|
||||
|
||||
//no found if null/empty
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getElementValue(element);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the ElementRecord for the given key, or null if not found
|
||||
* @param key the field/key to find
|
||||
* @return ElementRecord for key, or null
|
||||
*/
|
||||
ElementRecord getElement(String key){
|
||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
||||
|
||||
while ( !isElementEmpty( offset ) ){
|
||||
int fieldSize = sizeCString( offset + 1 );
|
||||
int elementSize = getElementBSONSize( offset );
|
||||
String name = _input.getCString( ++offset);
|
||||
|
||||
if (name.equals(key)) {
|
||||
return new ElementRecord( name, offset );
|
||||
}
|
||||
offset += ( fieldSize + elementSize);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns all the ElementRecords in this document
|
||||
* @return list of ElementRecord
|
||||
*/
|
||||
List<ElementRecord> getElements(){
|
||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
||||
ArrayList<ElementRecord> elements = new ArrayList<LazyBSONObject.ElementRecord>();
|
||||
|
||||
while ( !isElementEmpty( offset ) ){
|
||||
int fieldSize = sizeCString( offset + 1 );
|
||||
int elementSize = getElementBSONSize( offset );
|
||||
String name = _input.getCString( ++offset );
|
||||
ElementRecord rec = new ElementRecord( name, offset );
|
||||
elements.add( rec );
|
||||
offset += ( fieldSize + elementSize );
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Map toMap(){
|
||||
throw new UnsupportedOperationException( "Not Supported" );
|
||||
}
|
||||
|
||||
public Object removeField( String key ){
|
||||
throw new UnsupportedOperationException( "Object is read only" );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean containsKey( String s ){
|
||||
return containsField( s );
|
||||
}
|
||||
|
||||
public boolean containsField( String s ){
|
||||
return keySet().contains( s );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the set of all keys in the document
|
||||
*/
|
||||
public Set<String> keySet(){
|
||||
return new LazyBSONKeySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be more efficient than using a combination of keySet() and get(String key)
|
||||
* @return the set of entries (key, value) in the document
|
||||
*/
|
||||
public Set<Map.Entry<String, Object>> entrySet(){
|
||||
return new LazyBSONEntrySet();
|
||||
}
|
||||
|
||||
protected boolean isElementEmpty( int offset ){
|
||||
return getElementType( offset ) == BSON.EOO;
|
||||
}
|
||||
|
||||
public boolean isEmpty(){
|
||||
return isElementEmpty( _doc_start_offset + FIRST_ELMT_OFFSET );
|
||||
}
|
||||
|
||||
private int getBSONSize( final int offset ){
|
||||
return _input.getInt( offset );
|
||||
}
|
||||
|
||||
public int getBSONSize(){
|
||||
return getBSONSize( _doc_start_offset );
|
||||
}
|
||||
|
||||
public int pipe(OutputStream os) throws IOException {
|
||||
os.write(_input.array(), _doc_start_offset, getBSONSize());
|
||||
return getBSONSize();
|
||||
}
|
||||
|
||||
private String getElementFieldName( final int offset ){
|
||||
return _input.getCString( offset );
|
||||
}
|
||||
|
||||
protected byte getElementType( final int offset ){
|
||||
return _input.get( offset );
|
||||
}
|
||||
|
||||
protected int getElementBSONSize( int offset ){
|
||||
int x = 0;
|
||||
byte type = getElementType( offset++ );
|
||||
int n = sizeCString( offset );
|
||||
int valueOffset = offset + n;
|
||||
switch ( type ){
|
||||
case BSON.EOO:
|
||||
case BSON.UNDEFINED:
|
||||
case BSON.NULL:
|
||||
case BSON.MAXKEY:
|
||||
case BSON.MINKEY:
|
||||
break;
|
||||
case BSON.BOOLEAN:
|
||||
x = 1;
|
||||
break;
|
||||
case BSON.NUMBER_INT:
|
||||
x = 4;
|
||||
break;
|
||||
case BSON.TIMESTAMP:
|
||||
case BSON.DATE:
|
||||
case BSON.NUMBER_LONG:
|
||||
case BSON.NUMBER:
|
||||
x = 8;
|
||||
break;
|
||||
case BSON.OID:
|
||||
x = 12;
|
||||
break;
|
||||
case BSON.SYMBOL:
|
||||
case BSON.CODE:
|
||||
case BSON.STRING:
|
||||
x = _input.getInt( valueOffset ) + 4;
|
||||
break;
|
||||
case BSON.CODE_W_SCOPE:
|
||||
x = _input.getInt( valueOffset );
|
||||
break;
|
||||
case BSON.REF:
|
||||
x = _input.getInt( valueOffset ) + 4 + 12;
|
||||
break;
|
||||
case BSON.OBJECT:
|
||||
case BSON.ARRAY:
|
||||
x = _input.getInt( valueOffset );
|
||||
break;
|
||||
case BSON.BINARY:
|
||||
x = _input.getInt( valueOffset ) + 4 + 1/*subtype*/;
|
||||
break;
|
||||
case BSON.REGEX:
|
||||
// 2 cstrs
|
||||
int part1 = sizeCString( valueOffset );
|
||||
int part2 = sizeCString( valueOffset + part1 );
|
||||
x = part1 + part2;
|
||||
break;
|
||||
default:
|
||||
throw new BSONException( "Invalid type " + type + " for field " + getElementFieldName( offset ) );
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the size of the BSON cstring at the given offset in the buffer
|
||||
* @param offset the offset into the buffer
|
||||
* @return the size of the BSON cstring, including the null terminator
|
||||
*/
|
||||
protected int sizeCString( int offset ){
|
||||
int end = offset;
|
||||
while ( true ){
|
||||
byte b = _input.get( end );
|
||||
if ( b == 0 )
|
||||
break;
|
||||
else
|
||||
end++;
|
||||
}
|
||||
return end - offset + 1;
|
||||
}
|
||||
|
||||
protected Object getElementValue( ElementRecord record ){
|
||||
switch ( record.type ){
|
||||
case BSON.EOO:
|
||||
case BSON.UNDEFINED:
|
||||
case BSON.NULL:
|
||||
return null;
|
||||
case BSON.MAXKEY:
|
||||
return new MaxKey();
|
||||
case BSON.MINKEY:
|
||||
return new MinKey();
|
||||
case BSON.BOOLEAN:
|
||||
return ( _input.get( record.valueOffset ) != 0 );
|
||||
case BSON.NUMBER_INT:
|
||||
return _input.getInt( record.valueOffset );
|
||||
case BSON.TIMESTAMP:
|
||||
int inc = _input.getInt( record.valueOffset );
|
||||
int time = _input.getInt( record.valueOffset + 4 );
|
||||
return new BSONTimestamp( time, inc );
|
||||
case BSON.DATE:
|
||||
return new Date( _input.getLong( record.valueOffset ) );
|
||||
case BSON.NUMBER_LONG:
|
||||
return _input.getLong( record.valueOffset );
|
||||
case BSON.NUMBER:
|
||||
return Double.longBitsToDouble( _input.getLong( record.valueOffset ) );
|
||||
case BSON.OID:
|
||||
return new ObjectId( _input.getIntBE( record.valueOffset ),
|
||||
_input.getIntBE( record.valueOffset + 4 ),
|
||||
_input.getIntBE( record.valueOffset + 8 ) );
|
||||
case BSON.SYMBOL:
|
||||
return new Symbol( _input.getUTF8String( record.valueOffset ) );
|
||||
case BSON.CODE:
|
||||
return new Code( _input.getUTF8String( record.valueOffset ) );
|
||||
case BSON.STRING:
|
||||
return _input.getUTF8String( record.valueOffset );
|
||||
case BSON.CODE_W_SCOPE:
|
||||
int strsize = _input.getInt( record.valueOffset + 4 );
|
||||
String code = _input.getUTF8String( record.valueOffset + 4 );
|
||||
BSONObject scope =
|
||||
(BSONObject) _callback.createObject( _input.array(), record.valueOffset + 4 + 4 + strsize );
|
||||
return new CodeWScope( code, scope );
|
||||
case BSON.REF:
|
||||
int csize = _input.getInt( record.valueOffset );
|
||||
String ns = _input.getCString( record.valueOffset + 4 );
|
||||
int oidOffset = record.valueOffset + csize + 4;
|
||||
ObjectId oid = new ObjectId( _input.getIntBE( oidOffset ),
|
||||
_input.getIntBE( oidOffset + 4 ),
|
||||
_input.getIntBE( oidOffset + 8 ) );
|
||||
return _callback.createDBRef( ns, oid );
|
||||
case BSON.OBJECT:
|
||||
return _callback.createObject( _input.array(), record.valueOffset );
|
||||
case BSON.ARRAY:
|
||||
return _callback.createArray( _input.array(), record.valueOffset );
|
||||
case BSON.BINARY:
|
||||
return readBinary( record.valueOffset );
|
||||
case BSON.REGEX:
|
||||
int patternCStringSize = sizeCString( record.valueOffset );
|
||||
String pattern = _input.getCString( record.valueOffset );
|
||||
String flags = _input.getCString( record.valueOffset + patternCStringSize + 1 );
|
||||
return Pattern.compile( pattern, BSON.regexFlags( flags ) );
|
||||
default:
|
||||
throw new BSONException(
|
||||
"Invalid type " + record.type + " for field " + getElementFieldName( record.offset ) );
|
||||
}
|
||||
}
|
||||
|
||||
private Object readBinary( int valueOffset ){
|
||||
final int totalLen = _input.getInt( valueOffset );
|
||||
valueOffset += 4;
|
||||
final byte bType = _input.get( valueOffset );
|
||||
valueOffset += 1;
|
||||
|
||||
byte[] bin;
|
||||
switch ( bType ){
|
||||
case BSON.B_GENERAL:{
|
||||
bin = new byte[totalLen];
|
||||
for ( int n = 0; n < totalLen; n++ ){
|
||||
bin[n] = _input.get( valueOffset + n );
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
case BSON.B_BINARY:
|
||||
final int len = _input.getInt( valueOffset );
|
||||
if ( len + 4 != totalLen )
|
||||
throw new IllegalArgumentException(
|
||||
"Bad Data Size; Binary Subtype 2. { actual len: " + len + " expected totalLen: " + totalLen
|
||||
+ "}" );
|
||||
valueOffset += 4;
|
||||
bin = new byte[len];
|
||||
for ( int n = 0; n < len; n++ ){
|
||||
bin[n] = _input.get( valueOffset + n );
|
||||
}
|
||||
return bin;
|
||||
case BSON.B_UUID:
|
||||
if ( totalLen != 16 )
|
||||
throw new IllegalArgumentException(
|
||||
"Bad Data Size; Binary Subtype 3 (UUID). { total length: " + totalLen + " != 16" );
|
||||
|
||||
long part1 = _input.getLong( valueOffset );
|
||||
valueOffset += 8;
|
||||
long part2 = _input.getLong( valueOffset );
|
||||
return new UUID( part1, part2 );
|
||||
}
|
||||
|
||||
bin = new byte[totalLen];
|
||||
for ( int n = 0; n < totalLen; n++ ){
|
||||
bin[n] = _input.get( valueOffset + n );
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
LazyBSONObject that = (LazyBSONObject) o;
|
||||
|
||||
return Arrays.equals(this._input.array(), that._input.array());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(_input.array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON serialization of this object
|
||||
*
|
||||
* @return JSON serialization
|
||||
*/
|
||||
public String toString(){
|
||||
return com.massivecraft.mcore4.lib.mongodb.util.JSON.serialize( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* In a "normal" (aka not embedded) doc, this will be the offset of the first element.
|
||||
*
|
||||
* In an embedded doc because we use ByteBuffers to avoid unecessary copying the offset must be manually set in
|
||||
* _doc_start_offset
|
||||
*/
|
||||
final static int FIRST_ELMT_OFFSET = 4;
|
||||
|
||||
protected final int _doc_start_offset;
|
||||
|
||||
protected final BSONByteBuffer _input; // TODO - Guard this with synchronicity?
|
||||
// callback is kept to create sub-objects on the fly
|
||||
protected final LazyBSONCallback _callback;
|
||||
@SuppressWarnings("unused")
|
||||
private static final Logger log = Logger.getLogger( "org.bson.LazyBSONObject" );
|
||||
}
|
||||
42
src/com/massivecraft/mcore4/lib/bson/LazyDBList.java
Normal file
42
src/com/massivecraft/mcore4/lib/bson/LazyDBList.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.massivecraft.mcore4.lib.bson;
|
||||
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.BSONByteBuffer;
|
||||
import com.massivecraft.mcore4.lib.mongodb.DBObject;
|
||||
import com.massivecraft.mcore4.lib.mongodb.util.JSON;
|
||||
|
||||
/**
|
||||
* @author scotthernandez
|
||||
*
|
||||
*/
|
||||
public class LazyDBList extends LazyBSONList implements DBObject {
|
||||
@SuppressWarnings("unused")
|
||||
private static final long serialVersionUID = -4415279469780082174L;
|
||||
|
||||
public LazyDBList(byte[] data, LazyBSONCallback callback) { super(data, callback); }
|
||||
public LazyDBList(byte[] data, int offset, LazyBSONCallback callback) { super(data, offset, callback); }
|
||||
public LazyDBList(BSONByteBuffer buffer, LazyBSONCallback callback) { super(buffer, callback); }
|
||||
public LazyDBList(BSONByteBuffer buffer, int offset, LazyBSONCallback callback) { super(buffer, offset, callback); }
|
||||
|
||||
/**
|
||||
* Returns a JSON serialization of this object
|
||||
* @return JSON serialization
|
||||
*/
|
||||
@Override
|
||||
public String toString(){
|
||||
return JSON.serialize( this );
|
||||
}
|
||||
|
||||
public boolean isPartialObject(){
|
||||
return _isPartialObject;
|
||||
}
|
||||
|
||||
public void markAsPartialObject(){
|
||||
_isPartialObject = true;
|
||||
}
|
||||
|
||||
private boolean _isPartialObject;
|
||||
}
|
||||
304
src/com/massivecraft/mcore4/lib/bson/NewBSONDecoder.java
Normal file
304
src/com/massivecraft/mcore4/lib/bson/NewBSONDecoder.java
Normal file
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* Copyright (C) 2012 10gen 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.mcore4.lib.bson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.io.Bits;
|
||||
import com.massivecraft.mcore4.lib.bson.types.ObjectId;
|
||||
|
||||
import static com.massivecraft.mcore4.lib.bson.BSON.*;
|
||||
|
||||
// Java
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* A new implementation of the bson decoder.
|
||||
*/
|
||||
public class NewBSONDecoder implements BSONDecoder {
|
||||
|
||||
@Override
|
||||
public BSONObject readObject(final byte [] pData) {
|
||||
_length = pData.length;
|
||||
final BasicBSONCallback c = new BasicBSONCallback();
|
||||
decode(pData, c);
|
||||
return (BSONObject)c.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BSONObject readObject(final InputStream pIn) throws IOException {
|
||||
// Slurp in the data and convert to a byte array.
|
||||
_length = Bits.readInt(pIn);
|
||||
|
||||
if (_data == null || _data.length < _length) {
|
||||
_data = new byte[_length];
|
||||
}
|
||||
|
||||
(new DataInputStream(pIn)).readFully(_data, 4, (_length - 4));
|
||||
|
||||
return readObject(_data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decode(final byte [] pData, final BSONCallback pCallback) {
|
||||
_data = pData;
|
||||
_pos = 4;
|
||||
_callback = pCallback;
|
||||
_decode();
|
||||
return _length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int decode(final InputStream pIn, final BSONCallback pCallback) throws IOException {
|
||||
_length = Bits.readInt(pIn);
|
||||
|
||||
if (_data == null || _data.length < _length) {
|
||||
_data = new byte[_length];
|
||||
}
|
||||
|
||||
(new DataInputStream(pIn)).readFully(_data, 4, (_length - 4));
|
||||
|
||||
return decode(_data, pCallback);
|
||||
}
|
||||
|
||||
private final void _decode() {
|
||||
_callback.objectStart();
|
||||
while (decodeElement());
|
||||
_callback.objectDone();
|
||||
}
|
||||
|
||||
private final String readCstr() {
|
||||
int length = 0;
|
||||
final int offset = _pos;
|
||||
|
||||
while (_data[_pos++] != 0) length++;
|
||||
|
||||
try {
|
||||
return new String(_data, offset, length, DEFAULT_ENCODING);
|
||||
} catch (final UnsupportedEncodingException uee) {
|
||||
return new String(_data, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
private final String readUtf8Str() {
|
||||
final int length = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
if (length <= 0 || length > MAX_STRING) throw new BSONException("String invalid - corruption");
|
||||
|
||||
try {
|
||||
final String str = new String(_data, _pos, (length - 1), DEFAULT_ENCODING);
|
||||
_pos += length;
|
||||
return str;
|
||||
|
||||
} catch (final UnsupportedEncodingException uee) {
|
||||
throw new BSONException("What is in the db", uee);
|
||||
}
|
||||
}
|
||||
|
||||
private final Object _readBasicObject() {
|
||||
_pos += 4;
|
||||
|
||||
final BSONCallback save = _callback;
|
||||
final BSONCallback _basic = _callback.createBSONCallback();
|
||||
_callback = _basic;
|
||||
_basic.reset();
|
||||
_basic.objectStart(false);
|
||||
|
||||
while( decodeElement() );
|
||||
_callback = save;
|
||||
return _basic.get();
|
||||
}
|
||||
|
||||
private final void _binary(final String pName) {
|
||||
|
||||
final int totalLen = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
final byte bType = _data[_pos];
|
||||
_pos += 1;
|
||||
|
||||
switch ( bType ){
|
||||
case B_GENERAL: {
|
||||
final byte [] data = new byte[totalLen];
|
||||
|
||||
System.arraycopy(_data, _pos, data, 0, totalLen);
|
||||
_pos += totalLen;
|
||||
|
||||
_callback.gotBinary(pName, bType, data);
|
||||
return;
|
||||
}
|
||||
|
||||
case B_BINARY: {
|
||||
final int len = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
if ( len + 4 != totalLen )
|
||||
throw new IllegalArgumentException( "bad data size subtype 2 len: " + len + " totalLen: " + totalLen );
|
||||
|
||||
final byte [] data = new byte[len];
|
||||
System.arraycopy(_data, _pos, data, 0, len);
|
||||
_pos += len;
|
||||
_callback.gotBinary(pName, bType, data);
|
||||
return;
|
||||
}
|
||||
|
||||
case B_UUID: {
|
||||
if ( totalLen != 16 )
|
||||
throw new IllegalArgumentException( "bad data size subtype 3 len: " + totalLen + " != 16");
|
||||
|
||||
final long part1 = Bits.readLong(_data, _pos);
|
||||
_pos += 8;
|
||||
|
||||
final long part2 = Bits.readLong(_data, _pos);
|
||||
_pos += 8;
|
||||
|
||||
_callback.gotUUID(pName, part1, part2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final byte [] data = new byte[totalLen];
|
||||
System.arraycopy(_data, _pos, data, 0, totalLen);
|
||||
_pos += totalLen;
|
||||
|
||||
_callback.gotBinary(pName, bType, data);
|
||||
}
|
||||
|
||||
private final boolean decodeElement() {
|
||||
|
||||
final byte type = _data[_pos];
|
||||
_pos += 1;
|
||||
|
||||
if (type == EOO) return false;
|
||||
|
||||
final String name = readCstr();
|
||||
|
||||
switch (type) {
|
||||
case NULL: { _callback.gotNull(name); return true; }
|
||||
|
||||
case UNDEFINED: { _callback.gotUndefined(name); return true; }
|
||||
|
||||
case BOOLEAN: { _callback.gotBoolean(name, (_data[_pos] > 0)); _pos += 1; return true; }
|
||||
|
||||
case NUMBER: { _callback.gotDouble(name, Double.longBitsToDouble(Bits.readLong(_data, _pos))); _pos += 8; return true; }
|
||||
|
||||
case NUMBER_INT: { _callback.gotInt(name, Bits.readInt(_data, _pos)); _pos += 4; return true; }
|
||||
|
||||
case NUMBER_LONG: {
|
||||
_callback.gotLong(name, Bits.readLong(_data, _pos));
|
||||
_pos += 8;
|
||||
return true;
|
||||
}
|
||||
|
||||
case SYMBOL: { _callback.gotSymbol(name, readUtf8Str()); return true; }
|
||||
case STRING: { _callback.gotString(name, readUtf8Str()); return true; }
|
||||
|
||||
case OID: {
|
||||
// OID is stored as big endian
|
||||
|
||||
final int p1 = Bits.readIntBE(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
final int p2 = Bits.readIntBE(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
final int p3 = Bits.readIntBE(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
_callback.gotObjectId(name , new ObjectId(p1, p2, p3));
|
||||
return true;
|
||||
}
|
||||
|
||||
case REF: {
|
||||
_pos += 4;
|
||||
|
||||
final String ns = readCstr();
|
||||
|
||||
final int p1 = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
final int p2 = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
final int p3 = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
_callback.gotDBRef(name , ns, new ObjectId(p1, p2, p3));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case DATE: { _callback.gotDate(name , Bits.readLong(_data, _pos)); _pos += 8; return true; }
|
||||
|
||||
|
||||
case REGEX: {
|
||||
_callback.gotRegex(name, readCstr(), readCstr());
|
||||
return true;
|
||||
}
|
||||
|
||||
case BINARY: { _binary(name); return true; }
|
||||
|
||||
case CODE: { _callback.gotCode(name, readUtf8Str()); return true; }
|
||||
|
||||
case CODE_W_SCOPE: {
|
||||
_pos += 4;
|
||||
_callback.gotCodeWScope(name, readUtf8Str(), _readBasicObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
case ARRAY:
|
||||
_pos += 4;
|
||||
_callback.arrayStart(name);
|
||||
while (decodeElement());
|
||||
_callback.arrayDone();
|
||||
return true;
|
||||
|
||||
case OBJECT:
|
||||
_pos += 4;
|
||||
_callback.objectStart(name);
|
||||
while (decodeElement());
|
||||
_callback.objectDone();
|
||||
return true;
|
||||
|
||||
case TIMESTAMP:
|
||||
int i = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
int time = Bits.readInt(_data, _pos);
|
||||
_pos += 4;
|
||||
|
||||
_callback.gotTimestamp(name, time, i);
|
||||
return true;
|
||||
|
||||
case MINKEY: _callback.gotMinKey(name); return true;
|
||||
case MAXKEY: _callback.gotMaxKey(name); return true;
|
||||
|
||||
default: throw new UnsupportedOperationException( "BSONDecoder doesn't understand type : " + type + " name: " + name );
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MAX_STRING = ( 32 * 1024 * 1024 );
|
||||
private static final String DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
private byte [] _data;
|
||||
private int _length;
|
||||
private int _pos = 0;
|
||||
private BSONCallback _callback;
|
||||
}
|
||||
|
||||
27
src/com/massivecraft/mcore4/lib/bson/Transformer.java
Normal file
27
src/com/massivecraft/mcore4/lib/bson/Transformer.java
Normal file
@@ -0,0 +1,27 @@
|
||||
// Transformer.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson;
|
||||
|
||||
public interface Transformer {
|
||||
|
||||
/**
|
||||
* @return the new object. return passed in object if no change
|
||||
*/
|
||||
public Object transform( Object o );
|
||||
}
|
||||
143
src/com/massivecraft/mcore4/lib/bson/io/BSONByteBuffer.java
Normal file
143
src/com/massivecraft/mcore4/lib/bson/io/BSONByteBuffer.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Copyright (C) 2008-2011 10gen 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.mcore4.lib.bson.io;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
|
||||
/**
|
||||
* Pseudo byte buffer, delegates as it is too hard to properly override / extend the ByteBuffer API
|
||||
*
|
||||
* @author brendan
|
||||
*/
|
||||
public class BSONByteBuffer {
|
||||
|
||||
private BSONByteBuffer( ByteBuffer buf ){
|
||||
this.buf = buf;
|
||||
buf.order( ByteOrder.LITTLE_ENDIAN );
|
||||
}
|
||||
|
||||
public static BSONByteBuffer wrap( byte[] bytes, int offset, int length ){
|
||||
return new BSONByteBuffer( ByteBuffer.wrap( bytes, offset, length ) );
|
||||
}
|
||||
|
||||
public static BSONByteBuffer wrap( byte[] bytes ){
|
||||
return new BSONByteBuffer( ByteBuffer.wrap( bytes ) );
|
||||
}
|
||||
|
||||
public byte get( int i ){
|
||||
return buf.get(i);
|
||||
}
|
||||
|
||||
public ByteBuffer get( byte[] bytes, int offset, int length ){
|
||||
return buf.get(bytes, offset, length);
|
||||
}
|
||||
|
||||
public ByteBuffer get( byte[] bytes ){
|
||||
return buf.get(bytes);
|
||||
}
|
||||
|
||||
public byte[] array(){
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public int hashCode(){
|
||||
return buf.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
BSONByteBuffer that = (BSONByteBuffer) o;
|
||||
|
||||
if (buf != null ? !buf.equals(that.buf) : that.buf != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Little Endian Integer
|
||||
*
|
||||
* @param i Index to read from
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getInt( int i ){
|
||||
return getIntLE( i );
|
||||
}
|
||||
|
||||
public int getIntLE( int i ){
|
||||
int x = 0;
|
||||
x |= ( 0xFF & buf.get( i + 0 ) ) << 0;
|
||||
x |= ( 0xFF & buf.get( i + 1 ) ) << 8;
|
||||
x |= ( 0xFF & buf.get( i + 2 ) ) << 16;
|
||||
x |= ( 0xFF & buf.get( i + 3 ) ) << 24;
|
||||
return x;
|
||||
}
|
||||
|
||||
public int getIntBE( int i ){
|
||||
int x = 0;
|
||||
x |= ( 0xFF & buf.get( i + 0 ) ) << 24;
|
||||
x |= ( 0xFF & buf.get( i + 1 ) ) << 16;
|
||||
x |= ( 0xFF & buf.get( i + 2 ) ) << 8;
|
||||
x |= ( 0xFF & buf.get( i + 3 ) ) << 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
public long getLong( int i ){
|
||||
return buf.getLong( i );
|
||||
}
|
||||
|
||||
public String getCString(int offset) {
|
||||
int end = offset;
|
||||
while (get(end) != 0) {
|
||||
++end;
|
||||
}
|
||||
int len = end - offset;
|
||||
return new String(array(), offset, len);
|
||||
}
|
||||
|
||||
public String getUTF8String(int valueOffset) {
|
||||
int size = getInt(valueOffset) - 1;
|
||||
try {
|
||||
return new String(array(), valueOffset + 4, size, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new BSONException( "Cannot decode string as UTF-8." );
|
||||
}
|
||||
}
|
||||
|
||||
public Buffer position( int i ){
|
||||
return buf.position(i);
|
||||
}
|
||||
|
||||
public Buffer reset(){
|
||||
return buf.reset();
|
||||
}
|
||||
|
||||
public int size(){
|
||||
return getInt( 0 );
|
||||
}
|
||||
|
||||
protected ByteBuffer buf;
|
||||
}
|
||||
119
src/com/massivecraft/mcore4/lib/bson/io/BasicOutputBuffer.java
Normal file
119
src/com/massivecraft/mcore4/lib/bson/io/BasicOutputBuffer.java
Normal file
@@ -0,0 +1,119 @@
|
||||
// BasicOutputBuffer.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.io;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class BasicOutputBuffer extends OutputBuffer {
|
||||
|
||||
@Override
|
||||
public void write(byte[] b){
|
||||
write( b , 0 , b.length );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len){
|
||||
_ensure( len );
|
||||
System.arraycopy( b , off , _buffer , _cur , len );
|
||||
_cur += len;
|
||||
_size = Math.max( _cur , _size );
|
||||
}
|
||||
@Override
|
||||
public void write(int b){
|
||||
_ensure(1);
|
||||
_buffer[_cur++] = (byte)(0xFF&b);
|
||||
_size = Math.max( _cur , _size );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition(){
|
||||
return _cur;
|
||||
}
|
||||
@Override
|
||||
public void setPosition( int position ){
|
||||
_cur = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekEnd(){
|
||||
_cur = _size;
|
||||
}
|
||||
@Override
|
||||
public void seekStart(){
|
||||
_cur = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return size of data so far
|
||||
*/
|
||||
@Override
|
||||
public int size(){
|
||||
return _size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bytes written
|
||||
*/
|
||||
@Override
|
||||
public int pipe( OutputStream out )
|
||||
throws IOException {
|
||||
out.write( _buffer , 0 , _size );
|
||||
return _size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bytes written
|
||||
*/
|
||||
public int pipe( DataOutput out )
|
||||
throws IOException {
|
||||
out.write( _buffer , 0 , _size );
|
||||
return _size;
|
||||
}
|
||||
|
||||
|
||||
void _ensure( int more ){
|
||||
final int need = _cur + more;
|
||||
if ( need < _buffer.length )
|
||||
return;
|
||||
|
||||
int newSize = _buffer.length*2;
|
||||
if ( newSize <= need )
|
||||
newSize = need + 128;
|
||||
|
||||
byte[] n = new byte[newSize];
|
||||
System.arraycopy( _buffer , 0 , n , 0 , _size );
|
||||
_buffer = n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString(){
|
||||
return new String( _buffer , 0 , _size );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString( String encoding )
|
||||
throws UnsupportedEncodingException {
|
||||
return new String( _buffer , 0 , _size , encoding );
|
||||
}
|
||||
|
||||
|
||||
private int _cur;
|
||||
private int _size;
|
||||
private byte[] _buffer = new byte[512];
|
||||
}
|
||||
115
src/com/massivecraft/mcore4/lib/bson/io/Bits.java
Normal file
115
src/com/massivecraft/mcore4/lib/bson/io/Bits.java
Normal file
@@ -0,0 +1,115 @@
|
||||
// Bits.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.io;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class Bits {
|
||||
|
||||
public static void readFully( InputStream in, byte[] b )
|
||||
throws IOException {
|
||||
readFully( in , b , b.length );
|
||||
}
|
||||
|
||||
public static void readFully( InputStream in, byte[] b, int length )
|
||||
throws IOException {
|
||||
readFully(in, b, 0, length);
|
||||
}
|
||||
|
||||
public static void readFully( InputStream in, byte[] b, int startOffset, int length )
|
||||
throws IOException {
|
||||
|
||||
if (b.length - startOffset > length) {
|
||||
throw new IllegalArgumentException("Buffer is too small");
|
||||
}
|
||||
|
||||
int offset = startOffset;
|
||||
int toRead = length;
|
||||
while ( toRead > 0 ){
|
||||
int bytesRead = in.read( b, offset , toRead );
|
||||
if ( bytesRead < 0 )
|
||||
throw new EOFException();
|
||||
toRead -= bytesRead;
|
||||
offset += bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
public static int readInt( InputStream in )
|
||||
throws IOException {
|
||||
return readInt( in , new byte[4] );
|
||||
}
|
||||
|
||||
public static int readInt( InputStream in , byte[] data )
|
||||
throws IOException {
|
||||
readFully(in, data, 4);
|
||||
return readInt(data);
|
||||
}
|
||||
|
||||
public static int readInt( byte[] data ) {
|
||||
return readInt( data , 0 );
|
||||
}
|
||||
|
||||
public static int readInt( byte[] data , int offset ) {
|
||||
int x = 0;
|
||||
x |= ( 0xFF & data[offset+0] ) << 0;
|
||||
x |= ( 0xFF & data[offset+1] ) << 8;
|
||||
x |= ( 0xFF & data[offset+2] ) << 16;
|
||||
x |= ( 0xFF & data[offset+3] ) << 24;
|
||||
return x;
|
||||
}
|
||||
|
||||
public static int readIntBE( byte[] data , int offset ) {
|
||||
int x = 0;
|
||||
x |= ( 0xFF & data[offset+0] ) << 24;
|
||||
x |= ( 0xFF & data[offset+1] ) << 16;
|
||||
x |= ( 0xFF & data[offset+2] ) << 8;
|
||||
x |= ( 0xFF & data[offset+3] ) << 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
public static long readLong( InputStream in )
|
||||
throws IOException {
|
||||
return readLong( in , new byte[8] );
|
||||
}
|
||||
|
||||
|
||||
public static long readLong( InputStream in , byte[] data )
|
||||
throws IOException {
|
||||
readFully(in, data, 8);
|
||||
return readLong(data);
|
||||
}
|
||||
|
||||
public static long readLong( byte[] data ) {
|
||||
return readLong( data , 0 );
|
||||
}
|
||||
|
||||
public static long readLong( byte[] data , int offset ) {
|
||||
long x = 0;
|
||||
x |= ( 0xFFL & data[offset+0] ) << 0;
|
||||
x |= ( 0xFFL & data[offset+1] ) << 8;
|
||||
x |= ( 0xFFL & data[offset+2] ) << 16;
|
||||
x |= ( 0xFFL & data[offset+3] ) << 24;
|
||||
x |= ( 0xFFL & data[offset+4] ) << 32;
|
||||
x |= ( 0xFFL & data[offset+5] ) << 40;
|
||||
x |= ( 0xFFL & data[offset+6] ) << 48;
|
||||
x |= ( 0xFFL & data[offset+7] ) << 56;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
159
src/com/massivecraft/mcore4/lib/bson/io/OutputBuffer.java
Normal file
159
src/com/massivecraft/mcore4/lib/bson/io/OutputBuffer.java
Normal file
@@ -0,0 +1,159 @@
|
||||
// OutputBuffer.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.io;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.*;
|
||||
|
||||
public abstract class OutputBuffer extends OutputStream {
|
||||
|
||||
public abstract void write(byte[] b);
|
||||
public abstract void write(byte[] b, int off, int len);
|
||||
public abstract void write(int b);
|
||||
|
||||
public abstract int getPosition();
|
||||
public abstract void setPosition( int position );
|
||||
|
||||
public abstract void seekEnd();
|
||||
public abstract void seekStart();
|
||||
|
||||
/**
|
||||
* @return size of data so far
|
||||
*/
|
||||
public abstract int size();
|
||||
|
||||
/**
|
||||
* @return bytes written
|
||||
*/
|
||||
public abstract int pipe( OutputStream out )
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* mostly for testing
|
||||
*/
|
||||
public byte [] toByteArray(){
|
||||
try {
|
||||
final ByteArrayOutputStream bout = new ByteArrayOutputStream( size() );
|
||||
pipe( bout );
|
||||
return bout.toByteArray();
|
||||
}
|
||||
catch ( IOException ioe ){
|
||||
throw new RuntimeException( "should be impossible" , ioe );
|
||||
}
|
||||
}
|
||||
|
||||
public String asString(){
|
||||
return new String( toByteArray() );
|
||||
}
|
||||
|
||||
public String asString( String encoding )
|
||||
throws UnsupportedEncodingException {
|
||||
return new String( toByteArray() , encoding );
|
||||
}
|
||||
|
||||
|
||||
public String hex(){
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
try {
|
||||
pipe( new OutputStream(){
|
||||
public void write( int b ){
|
||||
String s = Integer.toHexString(0xff & b);
|
||||
|
||||
if (s.length() < 2)
|
||||
buf.append("0");
|
||||
buf.append(s);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch ( IOException ioe ){
|
||||
throw new RuntimeException( "impossible" );
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String md5(){
|
||||
final MessageDigest md5 ;
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
}
|
||||
catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Error - this implementation of Java doesn't support MD5.");
|
||||
}
|
||||
md5.reset();
|
||||
|
||||
try {
|
||||
pipe( new OutputStream(){
|
||||
public void write( byte[] b , int off , int len ){
|
||||
md5.update( b , off , len );
|
||||
}
|
||||
|
||||
public void write( int b ){
|
||||
md5.update( (byte)(b&0xFF) );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch ( IOException ioe ){
|
||||
throw new RuntimeException( "impossible" );
|
||||
}
|
||||
|
||||
return com.massivecraft.mcore4.lib.mongodb.util.Util.toHex( md5.digest() );
|
||||
}
|
||||
|
||||
public void writeInt( int x ){
|
||||
write( x >> 0 );
|
||||
write( x >> 8 );
|
||||
write( x >> 16 );
|
||||
write( x >> 24 );
|
||||
}
|
||||
|
||||
public void writeIntBE( int x ){
|
||||
write( x >> 24 );
|
||||
write( x >> 16 );
|
||||
write( x >> 8 );
|
||||
write( x );
|
||||
}
|
||||
|
||||
public void writeInt( int pos , int x ){
|
||||
final int save = getPosition();
|
||||
setPosition( pos );
|
||||
writeInt( x );
|
||||
setPosition( save );
|
||||
}
|
||||
|
||||
public void writeLong( long x ){
|
||||
write( (byte)(0xFFL & ( x >> 0 ) ) );
|
||||
write( (byte)(0xFFL & ( x >> 8 ) ) );
|
||||
write( (byte)(0xFFL & ( x >> 16 ) ) );
|
||||
write( (byte)(0xFFL & ( x >> 24 ) ) );
|
||||
write( (byte)(0xFFL & ( x >> 32 ) ) );
|
||||
write( (byte)(0xFFL & ( x >> 40 ) ) );
|
||||
write( (byte)(0xFFL & ( x >> 48 ) ) );
|
||||
write( (byte)(0xFFL & ( x >> 56 ) ) );
|
||||
}
|
||||
|
||||
public void writeDouble( double x ){
|
||||
writeLong( Double.doubleToRawLongBits( x ) );
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return getClass().getName() + " size: " + size() + " pos: " + getPosition() ;
|
||||
}
|
||||
}
|
||||
239
src/com/massivecraft/mcore4/lib/bson/io/PoolOutputBuffer.java
Normal file
239
src/com/massivecraft/mcore4/lib/bson/io/PoolOutputBuffer.java
Normal file
@@ -0,0 +1,239 @@
|
||||
// PoolOutputBuffer.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.io;
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class PoolOutputBuffer extends OutputBuffer {
|
||||
|
||||
public static final int BUF_SIZE = 1024 * 16;
|
||||
|
||||
public PoolOutputBuffer(){
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
_cur.reset();
|
||||
_end.reset();
|
||||
|
||||
for ( int i=0; i<_fromPool.size(); i++ )
|
||||
_extra.done( _fromPool.get(i) );
|
||||
_fromPool.clear();
|
||||
}
|
||||
|
||||
public int getPosition(){
|
||||
return _cur.pos();
|
||||
}
|
||||
|
||||
public void setPosition( int position ){
|
||||
_cur.reset( position );
|
||||
}
|
||||
|
||||
public void seekEnd(){
|
||||
_cur.reset( _end );
|
||||
}
|
||||
|
||||
public void seekStart(){
|
||||
_cur.reset();
|
||||
}
|
||||
|
||||
|
||||
public int size(){
|
||||
return _end.pos();
|
||||
}
|
||||
|
||||
public void write(byte[] b){
|
||||
write( b , 0 , b.length );
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len){
|
||||
while ( len > 0 ){
|
||||
byte[] bs = _cur();
|
||||
int space = Math.min( bs.length - _cur.y , len );
|
||||
System.arraycopy( b , off , bs , _cur.y , space );
|
||||
_cur.inc( space );
|
||||
len -= space;
|
||||
off += space;
|
||||
_afterWrite();
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int b){
|
||||
byte[] bs = _cur();
|
||||
bs[_cur.getAndInc()] = (byte)(b&0xFF);
|
||||
_afterWrite();
|
||||
}
|
||||
|
||||
void _afterWrite(){
|
||||
|
||||
if ( _cur.pos() < _end.pos() ){
|
||||
// we're in the middle of the total space
|
||||
// just need to make sure we're not at the end of a buffer
|
||||
if ( _cur.y == BUF_SIZE )
|
||||
_cur.nextBuffer();
|
||||
return;
|
||||
}
|
||||
|
||||
_end.reset( _cur );
|
||||
|
||||
if ( _end.y < BUF_SIZE )
|
||||
return;
|
||||
|
||||
_fromPool.add( _extra.get() );
|
||||
_end.nextBuffer();
|
||||
_cur.reset( _end );
|
||||
}
|
||||
|
||||
byte[] _cur(){
|
||||
return _get( _cur.x );
|
||||
}
|
||||
|
||||
byte[] _get( int z ){
|
||||
if ( z < 0 )
|
||||
return _mine;
|
||||
return _fromPool.get(z);
|
||||
}
|
||||
|
||||
public int pipe( final OutputStream out )
|
||||
throws IOException {
|
||||
|
||||
if ( out == null )
|
||||
throw new NullPointerException( "out is null" );
|
||||
|
||||
int total = 0;
|
||||
|
||||
for ( int i=-1; i<_fromPool.size(); i++ ){
|
||||
final byte[] b = _get( i );
|
||||
final int amt = _end.len( i );
|
||||
out.write( b , 0 , amt );
|
||||
total += amt;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static class Position {
|
||||
Position(){
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset(){
|
||||
x = -1;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
void reset( Position other ){
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
}
|
||||
|
||||
void reset( int pos ){
|
||||
x = ( pos / BUF_SIZE ) - 1;
|
||||
y = pos % BUF_SIZE;
|
||||
}
|
||||
|
||||
int pos(){
|
||||
return ( ( x + 1 ) * BUF_SIZE ) + y;
|
||||
}
|
||||
|
||||
int getAndInc(){
|
||||
return y++;
|
||||
}
|
||||
|
||||
void inc( int amt ){
|
||||
y += amt;
|
||||
if ( y > BUF_SIZE )
|
||||
throw new IllegalArgumentException( "something is wrong" );
|
||||
}
|
||||
|
||||
void nextBuffer(){
|
||||
if ( y != BUF_SIZE )
|
||||
throw new IllegalArgumentException( "broken" );
|
||||
x++;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
int len( int which ){
|
||||
if ( which < x )
|
||||
return BUF_SIZE;
|
||||
return y;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return x + "," + y;
|
||||
}
|
||||
|
||||
int x; // which buffer -1 == _mine
|
||||
int y; // position in buffer
|
||||
}
|
||||
|
||||
public String asAscii(){
|
||||
if ( _fromPool.size() > 0 )
|
||||
return super.asString();
|
||||
|
||||
final int m = size();
|
||||
final char c[] = m < _chars.length ? _chars : new char[m];
|
||||
|
||||
for ( int i=0; i<m; i++ )
|
||||
c[i] = (char)_mine[i];
|
||||
|
||||
return new String( c , 0 , m );
|
||||
}
|
||||
|
||||
public String asString( String encoding )
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
|
||||
if ( _fromPool.size() > 0 )
|
||||
return super.asString( encoding );
|
||||
|
||||
if ( encoding.equals( DEFAULT_ENCODING_1 ) || encoding.equals( DEFAULT_ENCODING_2) ){
|
||||
try {
|
||||
return _encoding.decode( _mine , 0 , size() );
|
||||
}
|
||||
catch ( IOException ioe ){
|
||||
// we failed, fall back
|
||||
}
|
||||
}
|
||||
return new String( _mine , 0 , size() , encoding );
|
||||
}
|
||||
|
||||
|
||||
final byte[] _mine = new byte[BUF_SIZE];
|
||||
final char[] _chars = new char[BUF_SIZE];
|
||||
final List<byte[]> _fromPool = new ArrayList<byte[]>();
|
||||
final UTF8Encoding _encoding = new UTF8Encoding();
|
||||
|
||||
private static final String DEFAULT_ENCODING_1 = "UTF-8";
|
||||
private static final String DEFAULT_ENCODING_2 = "UTF8";
|
||||
|
||||
private final Position _cur = new Position();
|
||||
private final Position _end = new Position();
|
||||
|
||||
private static com.massivecraft.mcore4.lib.bson.util.SimplePool<byte[]> _extra =
|
||||
new com.massivecraft.mcore4.lib.bson.util.SimplePool<byte[]>( ( 1024 * 1024 * 10 ) / BUF_SIZE ){
|
||||
|
||||
protected byte[] createNew(){
|
||||
return new byte[BUF_SIZE];
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
202
src/com/massivecraft/mcore4/lib/bson/io/UTF8Encoding.java
Normal file
202
src/com/massivecraft/mcore4/lib/bson/io/UTF8Encoding.java
Normal file
@@ -0,0 +1,202 @@
|
||||
// UTF8Encoding.java
|
||||
|
||||
|
||||
/**
|
||||
* from postgresql jdbc driver:
|
||||
* postgresql-jdbc-9.0-801.src
|
||||
|
||||
|
||||
Copyright (c) 1997-2008, PostgreSQL Global Development Group
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the PostgreSQL Global Development Group nor the names
|
||||
of its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 2003-2008, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
*
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//package org.postgresql.core;
|
||||
package com.massivecraft.mcore4.lib.bson.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
|
||||
class UTF8Encoding {
|
||||
|
||||
private static final int MIN_2_BYTES = 0x80;
|
||||
private static final int MIN_3_BYTES = 0x800;
|
||||
private static final int MIN_4_BYTES = 0x10000;
|
||||
private static final int MAX_CODE_POINT = 0x10ffff;
|
||||
|
||||
private char[] decoderArray = new char[1024];
|
||||
|
||||
// helper for decode
|
||||
private final static void checkByte(int ch, int pos, int len) throws IOException {
|
||||
if ((ch & 0xc0) != 0x80)
|
||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: byte {0} of {1} byte sequence is not 10xxxxxx: {2}",
|
||||
new Object[] { new Integer(pos), new Integer(len), new Integer(ch) }));
|
||||
}
|
||||
|
||||
private final static void checkMinimal(int ch, int minValue) throws IOException {
|
||||
if (ch >= minValue)
|
||||
return;
|
||||
|
||||
int actualLen;
|
||||
switch (minValue) {
|
||||
case MIN_2_BYTES:
|
||||
actualLen = 2;
|
||||
break;
|
||||
case MIN_3_BYTES:
|
||||
actualLen = 3;
|
||||
break;
|
||||
case MIN_4_BYTES:
|
||||
actualLen = 4;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("unexpected minValue passed to checkMinimal: " + minValue);
|
||||
}
|
||||
|
||||
int expectedLen;
|
||||
if (ch < MIN_2_BYTES)
|
||||
expectedLen = 1;
|
||||
else if (ch < MIN_3_BYTES)
|
||||
expectedLen = 2;
|
||||
else if (ch < MIN_4_BYTES)
|
||||
expectedLen = 3;
|
||||
else
|
||||
throw new IllegalArgumentException("unexpected ch passed to checkMinimal: " + ch);
|
||||
|
||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: {0} bytes used to encode a {1} byte value: {2}",
|
||||
new Object[] { new Integer(actualLen), new Integer(expectedLen), new Integer(ch) }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom byte[] -> String conversion routine for UTF-8 only.
|
||||
* This is about twice as fast as using the String(byte[],int,int,String)
|
||||
* ctor, at least under JDK 1.4.2. The extra checks for illegal representations
|
||||
* add about 10-15% overhead, but they seem worth it given the number of SQL_ASCII
|
||||
* databases out there.
|
||||
*
|
||||
* @param data the array containing UTF8-encoded data
|
||||
* @param offset the offset of the first byte in <code>data</code> to decode from
|
||||
* @param length the number of bytes to decode
|
||||
* @return a decoded string
|
||||
* @throws IOException if something goes wrong
|
||||
*/
|
||||
public synchronized String decode(byte[] data, int offset, int length) throws IOException {
|
||||
char[] cdata = decoderArray;
|
||||
if (cdata.length < length)
|
||||
cdata = decoderArray = new char[length];
|
||||
|
||||
int in = offset;
|
||||
int out = 0;
|
||||
int end = length + offset;
|
||||
|
||||
try
|
||||
{
|
||||
while (in < end)
|
||||
{
|
||||
int ch = data[in++] & 0xff;
|
||||
|
||||
// Convert UTF-8 to 21-bit codepoint.
|
||||
if (ch < 0x80) {
|
||||
// 0xxxxxxx -- length 1.
|
||||
} else if (ch < 0xc0) {
|
||||
// 10xxxxxx -- illegal!
|
||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: initial byte is {0}: {1}",
|
||||
new Object[] { "10xxxxxx", new Integer(ch) }));
|
||||
} else if (ch < 0xe0) {
|
||||
// 110xxxxx 10xxxxxx
|
||||
ch = ((ch & 0x1f) << 6);
|
||||
checkByte(data[in], 2, 2);
|
||||
ch = ch | (data[in++] & 0x3f);
|
||||
checkMinimal(ch, MIN_2_BYTES);
|
||||
} else if (ch < 0xf0) {
|
||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||
ch = ((ch & 0x0f) << 12);
|
||||
checkByte(data[in], 2, 3);
|
||||
ch = ch | ((data[in++] & 0x3f) << 6);
|
||||
checkByte(data[in], 3, 3);
|
||||
ch = ch | (data[in++] & 0x3f);
|
||||
checkMinimal(ch, MIN_3_BYTES);
|
||||
} else if (ch < 0xf8) {
|
||||
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
ch = ((ch & 0x07) << 18);
|
||||
checkByte(data[in], 2, 4);
|
||||
ch = ch | ((data[in++] & 0x3f) << 12);
|
||||
checkByte(data[in], 3, 4);
|
||||
ch = ch | ((data[in++] & 0x3f) << 6);
|
||||
checkByte(data[in], 4, 4);
|
||||
ch = ch | (data[in++] & 0x3f);
|
||||
checkMinimal(ch, MIN_4_BYTES);
|
||||
} else {
|
||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: initial byte is {0}: {1}",
|
||||
new Object[] { "11111xxx", new Integer(ch) }));
|
||||
}
|
||||
|
||||
if (ch > MAX_CODE_POINT)
|
||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: final value is out of range: {0}",
|
||||
new Integer(ch)));
|
||||
|
||||
// Convert 21-bit codepoint to Java chars:
|
||||
// 0..ffff are represented directly as a single char
|
||||
// 10000..10ffff are represented as a "surrogate pair" of two chars
|
||||
// See: http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
|
||||
|
||||
if (ch > 0xffff) {
|
||||
// Use a surrogate pair to represent it.
|
||||
ch -= 0x10000; // ch is now 0..fffff (20 bits)
|
||||
cdata[out++] = (char) (0xd800 + (ch >> 10)); // top 10 bits
|
||||
cdata[out++] = (char) (0xdc00 + (ch & 0x3ff)); // bottom 10 bits
|
||||
} else if (ch >= 0xd800 && ch < 0xe000) {
|
||||
// Not allowed to encode the surrogate range directly.
|
||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: final value is a surrogate value: {0}",
|
||||
new Integer(ch)));
|
||||
} else {
|
||||
// Normal case.
|
||||
cdata[out++] = (char) ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException a)
|
||||
{
|
||||
throw new IOException("Illegal UTF-8 sequence: multibyte sequence was truncated");
|
||||
}
|
||||
|
||||
// Check if we ran past the end without seeing an exception.
|
||||
if (in > end)
|
||||
throw new IOException("Illegal UTF-8 sequence: multibyte sequence was truncated");
|
||||
|
||||
return new String(cdata, 0, out);
|
||||
}
|
||||
}
|
||||
3
src/com/massivecraft/mcore4/lib/bson/io/package.html
Normal file
3
src/com/massivecraft/mcore4/lib/bson/io/package.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
<p>Contains classes implementing I/O operations used by BSON objects.</p>
|
||||
</body>
|
||||
3
src/com/massivecraft/mcore4/lib/bson/package.html
Normal file
3
src/com/massivecraft/mcore4/lib/bson/package.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
<p>Contains the base BSON classes and Encoder/Decoder.</p>
|
||||
</body>
|
||||
@@ -0,0 +1,76 @@
|
||||
// BSONTimestamp.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* this is used for internal increment values.
|
||||
* for storing normal dates in MongoDB, you should use java.util.Date
|
||||
* <b>time</b> is seconds since epoch
|
||||
* <b>inc<b> is an ordinal
|
||||
*/
|
||||
public class BSONTimestamp implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3268482672267936464L;
|
||||
|
||||
static final boolean D = Boolean.getBoolean( "DEBUG.DBTIMESTAMP" );
|
||||
|
||||
public BSONTimestamp(){
|
||||
_inc = 0;
|
||||
_time = null;
|
||||
}
|
||||
|
||||
public BSONTimestamp(int time, int inc ){
|
||||
_time = new Date( time * 1000L );
|
||||
_inc = inc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return get time in seconds since epoch
|
||||
*/
|
||||
public int getTime(){
|
||||
if ( _time == null )
|
||||
return 0;
|
||||
return (int)(_time.getTime() / 1000);
|
||||
}
|
||||
|
||||
public int getInc(){
|
||||
return _inc;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return "TS time:" + _time + " inc:" + _inc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj instanceof BSONTimestamp) {
|
||||
BSONTimestamp t2 = (BSONTimestamp) obj;
|
||||
return getTime() == t2.getTime() && getInc() == t2.getInc();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final int _inc;
|
||||
final Date _time;
|
||||
}
|
||||
165
src/com/massivecraft/mcore4/lib/bson/types/BasicBSONList.java
Normal file
165
src/com/massivecraft/mcore4/lib/bson/types/BasicBSONList.java
Normal file
@@ -0,0 +1,165 @@
|
||||
// BasicBSONList.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.*;
|
||||
import com.massivecraft.mcore4.lib.bson.util.StringRangeSet;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Utility class to allow array <code>DBObject</code>s to be created.
|
||||
* <p>
|
||||
* Note: MongoDB will also create arrays from <code>java.util.List</code>s.
|
||||
* </p>
|
||||
* <p>
|
||||
* <blockquote><pre>
|
||||
* DBObject obj = new BasicBSONList();
|
||||
* obj.put( "0", value1 );
|
||||
* obj.put( "4", value2 );
|
||||
* obj.put( 2, value3 );
|
||||
* </pre></blockquote>
|
||||
* This simulates the array [ value1, null, value3, null, value2 ] by creating the
|
||||
* <code>DBObject</code> <code>{ "0" : value1, "1" : null, "2" : value3, "3" : null, "4" : value2 }</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* BasicBSONList only supports numeric keys. Passing strings that cannot be converted to ints will cause an
|
||||
* IllegalArgumentException.
|
||||
* <blockquote><pre>
|
||||
* BasicBSONList list = new BasicBSONList();
|
||||
* list.put("1", "bar"); // ok
|
||||
* list.put("1E1", "bar"); // throws exception
|
||||
* </pre></blockquote>
|
||||
* </p>
|
||||
*/
|
||||
public class BasicBSONList extends ArrayList<Object> implements BSONObject {
|
||||
|
||||
private static final long serialVersionUID = -4415279469780082174L;
|
||||
|
||||
public BasicBSONList() { }
|
||||
|
||||
/**
|
||||
* Puts a value at an index.
|
||||
* For interface compatibility. Must be passed a String that is parsable to an int.
|
||||
* @param key the index at which to insert the value
|
||||
* @param v the value to insert
|
||||
* @return the value
|
||||
* @throws IllegalArgumentException if <code>key</code> cannot be parsed into an <code>int</code>
|
||||
*/
|
||||
public Object put( String key , Object v ){
|
||||
return put(_getInt( key ), v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a value at an index.
|
||||
* This will fill any unset indexes less than <code>index</code> with <code>null</code>.
|
||||
* @param key the index at which to insert the value
|
||||
* @param v the value to insert
|
||||
* @return the value
|
||||
*/
|
||||
public Object put( int key, Object v ) {
|
||||
while ( key >= size() )
|
||||
add( null );
|
||||
set( key , v );
|
||||
return v;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void putAll( Map m ){
|
||||
for ( Map.Entry entry : (Set<Map.Entry>)m.entrySet() ){
|
||||
put( entry.getKey().toString() , entry.getValue() );
|
||||
}
|
||||
}
|
||||
|
||||
public void putAll( BSONObject o ){
|
||||
for ( String k : o.keySet() ){
|
||||
put( k , o.get( k ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value at an index.
|
||||
* For interface compatibility. Must be passed a String that is parsable to an int.
|
||||
* @param key the index
|
||||
* @return the value, if found, or null
|
||||
* @throws IllegalArgumentException if <code>key</code> cannot be parsed into an <code>int</code>
|
||||
*/
|
||||
public Object get( String key ){
|
||||
int i = _getInt( key );
|
||||
if ( i < 0 )
|
||||
return null;
|
||||
if ( i >= size() )
|
||||
return null;
|
||||
return get( i );
|
||||
}
|
||||
|
||||
public Object removeField( String key ){
|
||||
int i = _getInt( key );
|
||||
if ( i < 0 )
|
||||
return null;
|
||||
if ( i >= size() )
|
||||
return null;
|
||||
return remove( i );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean containsKey( String key ){
|
||||
return containsField(key);
|
||||
}
|
||||
|
||||
public boolean containsField( String key ){
|
||||
int i = _getInt( key , false );
|
||||
if ( i < 0 )
|
||||
return false;
|
||||
return i >= 0 && i < size();
|
||||
}
|
||||
|
||||
public Set<String> keySet(){
|
||||
return new StringRangeSet(size());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Map toMap() {
|
||||
Map m = new HashMap();
|
||||
Iterator i = this.keySet().iterator();
|
||||
while (i.hasNext()) {
|
||||
Object s = i.next();
|
||||
m.put(s, this.get(String.valueOf(s)));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
int _getInt( String s ){
|
||||
return _getInt( s , true );
|
||||
}
|
||||
|
||||
int _getInt( String s , boolean err ){
|
||||
try {
|
||||
return Integer.parseInt( s );
|
||||
}
|
||||
catch ( Exception e ){
|
||||
if ( err )
|
||||
throw new IllegalArgumentException( "BasicBSONList can only work with numeric keys, not: [" + s + "]" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/com/massivecraft/mcore4/lib/bson/types/Binary.java
Normal file
67
src/com/massivecraft/mcore4/lib/bson/types/Binary.java
Normal file
@@ -0,0 +1,67 @@
|
||||
// Binary.java
|
||||
|
||||
/**
|
||||
* See the NOTICE.txt file distributed with this work for
|
||||
* information regarding copyright ownership.
|
||||
*
|
||||
* The authors license this file to you 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.mcore4.lib.bson.types;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.BSON;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
generic binary holder
|
||||
*/
|
||||
public class Binary implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 7902997490338209467L;
|
||||
|
||||
/**
|
||||
* Creates a Binary object with the default binary type of 0
|
||||
* @param data raw data
|
||||
*/
|
||||
public Binary( byte[] data ){
|
||||
this(BSON.B_GENERAL, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Binary object
|
||||
* @param type type of the field as encoded in BSON
|
||||
* @param data raw data
|
||||
*/
|
||||
public Binary( byte type , byte[] data ){
|
||||
_type = type;
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public byte getType(){
|
||||
return _type;
|
||||
}
|
||||
|
||||
public byte[] getData(){
|
||||
return _data;
|
||||
}
|
||||
|
||||
public int length(){
|
||||
return _data.length;
|
||||
}
|
||||
|
||||
final byte _type;
|
||||
final byte[] _data;
|
||||
}
|
||||
58
src/com/massivecraft/mcore4/lib/bson/types/Code.java
Normal file
58
src/com/massivecraft/mcore4/lib/bson/types/Code.java
Normal file
@@ -0,0 +1,58 @@
|
||||
// Code.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* for using the Code type
|
||||
*/
|
||||
public class Code implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 475535263314046697L;
|
||||
|
||||
public Code( String code ){
|
||||
_code = code;
|
||||
}
|
||||
|
||||
public String getCode(){
|
||||
return _code;
|
||||
}
|
||||
|
||||
public boolean equals( Object o ){
|
||||
if ( ! ( o instanceof Code ) )
|
||||
return false;
|
||||
|
||||
Code c = (Code)o;
|
||||
return _code.equals( c._code );
|
||||
}
|
||||
|
||||
public int hashCode(){
|
||||
return _code.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getCode();
|
||||
}
|
||||
|
||||
final String _code;
|
||||
|
||||
}
|
||||
|
||||
53
src/com/massivecraft/mcore4/lib/bson/types/CodeWScope.java
Normal file
53
src/com/massivecraft/mcore4/lib/bson/types/CodeWScope.java
Normal file
@@ -0,0 +1,53 @@
|
||||
// CodeWScope.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.*;
|
||||
|
||||
/**
|
||||
* for using the CodeWScope type
|
||||
*/
|
||||
public class CodeWScope extends Code {
|
||||
|
||||
private static final long serialVersionUID = -6284832275113680002L;
|
||||
|
||||
public CodeWScope( String code , BSONObject scope ){
|
||||
super( code );
|
||||
_scope = scope;
|
||||
}
|
||||
|
||||
public BSONObject getScope(){
|
||||
return _scope;
|
||||
}
|
||||
|
||||
public boolean equals( Object o ){
|
||||
if ( ! ( o instanceof CodeWScope ) )
|
||||
return false;
|
||||
|
||||
CodeWScope c = (CodeWScope)o;
|
||||
return _code.equals( c._code ) && _scope.equals( c._scope );
|
||||
}
|
||||
|
||||
public int hashCode(){
|
||||
return _code.hashCode() ^ _scope.hashCode();
|
||||
}
|
||||
|
||||
final BSONObject _scope;
|
||||
}
|
||||
|
||||
47
src/com/massivecraft/mcore4/lib/bson/types/MaxKey.java
Normal file
47
src/com/massivecraft/mcore4/lib/bson/types/MaxKey.java
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represent the maximum key value regardless of the key's type
|
||||
*/
|
||||
public class MaxKey implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5123414776151687185L;
|
||||
|
||||
public MaxKey() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof MaxKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MaxKey";
|
||||
}
|
||||
|
||||
}
|
||||
47
src/com/massivecraft/mcore4/lib/bson/types/MinKey.java
Normal file
47
src/com/massivecraft/mcore4/lib/bson/types/MinKey.java
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Represent the minimum key value regardless of the key's type
|
||||
*/
|
||||
public class MinKey implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4075901136671855684L;
|
||||
|
||||
public MinKey() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof MinKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MinKey";
|
||||
}
|
||||
|
||||
}
|
||||
401
src/com/massivecraft/mcore4/lib/bson/types/ObjectId.java
Normal file
401
src/com/massivecraft/mcore4/lib/bson/types/ObjectId.java
Normal file
@@ -0,0 +1,401 @@
|
||||
// ObjectId.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import java.net.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
import java.util.logging.*;
|
||||
|
||||
/**
|
||||
* A globally unique identifier for objects.
|
||||
* <p>Consists of 12 bytes, divided as follows:
|
||||
* <blockquote><pre>
|
||||
* <table border="1">
|
||||
* <tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td>
|
||||
* <td>7</td><td>8</td><td>9</td><td>10</td><td>11</td></tr>
|
||||
* <tr><td colspan="4">time</td><td colspan="3">machine</td>
|
||||
* <td colspan="2">pid</td><td colspan="3">inc</td></tr>
|
||||
* </table>
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @dochub objectids
|
||||
*/
|
||||
public class ObjectId implements Comparable<ObjectId> , java.io.Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4415279469780082174L;
|
||||
|
||||
static final Logger LOGGER = Logger.getLogger( "org.bson.ObjectId" );
|
||||
|
||||
/** Gets a new object id.
|
||||
* @return the new id
|
||||
*/
|
||||
public static ObjectId get(){
|
||||
return new ObjectId();
|
||||
}
|
||||
|
||||
/** Checks if a string could be an <code>ObjectId</code>.
|
||||
* @return whether the string could be an object id
|
||||
*/
|
||||
public static boolean isValid( String s ){
|
||||
if ( s == null )
|
||||
return false;
|
||||
|
||||
final int len = s.length();
|
||||
if ( len != 24 )
|
||||
return false;
|
||||
|
||||
for ( int i=0; i<len; i++ ){
|
||||
char c = s.charAt( i );
|
||||
if ( c >= '0' && c <= '9' )
|
||||
continue;
|
||||
if ( c >= 'a' && c <= 'f' )
|
||||
continue;
|
||||
if ( c >= 'A' && c <= 'F' )
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Turn an object into an <code>ObjectId</code>, if possible.
|
||||
* Strings will be converted into <code>ObjectId</code>s, if possible, and <code>ObjectId</code>s will
|
||||
* be cast and returned. Passing in <code>null</code> returns <code>null</code>.
|
||||
* @param o the object to convert
|
||||
* @return an <code>ObjectId</code> if it can be massaged, null otherwise
|
||||
*/
|
||||
public static ObjectId massageToObjectId( Object o ){
|
||||
if ( o == null )
|
||||
return null;
|
||||
|
||||
if ( o instanceof ObjectId )
|
||||
return (ObjectId)o;
|
||||
|
||||
if ( o instanceof String ){
|
||||
String s = o.toString();
|
||||
if ( isValid( s ) )
|
||||
return new ObjectId( s );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ObjectId( Date time ){
|
||||
this(time, _genmachine, _nextInc.getAndIncrement());
|
||||
}
|
||||
|
||||
public ObjectId( Date time , int inc ){
|
||||
this( time , _genmachine , inc );
|
||||
}
|
||||
|
||||
public ObjectId( Date time , int machine , int inc ){
|
||||
_time = (int)(time.getTime() / 1000);
|
||||
_machine = machine;
|
||||
_inc = inc;
|
||||
_new = false;
|
||||
}
|
||||
|
||||
/** Creates a new instance from a string.
|
||||
* @param s the string to convert
|
||||
* @throws IllegalArgumentException if the string is not a valid id
|
||||
*/
|
||||
public ObjectId( String s ){
|
||||
this( s , false );
|
||||
}
|
||||
|
||||
public ObjectId( String s , boolean babble ){
|
||||
|
||||
if ( ! isValid( s ) )
|
||||
throw new IllegalArgumentException( "invalid ObjectId [" + s + "]" );
|
||||
|
||||
if ( babble )
|
||||
s = babbleToMongod( s );
|
||||
|
||||
byte b[] = new byte[12];
|
||||
for ( int i=0; i<b.length; i++ ){
|
||||
b[i] = (byte)Integer.parseInt( s.substring( i*2 , i*2 + 2) , 16 );
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap( b );
|
||||
_time = bb.getInt();
|
||||
_machine = bb.getInt();
|
||||
_inc = bb.getInt();
|
||||
_new = false;
|
||||
}
|
||||
|
||||
public ObjectId( byte[] b ){
|
||||
if ( b.length != 12 )
|
||||
throw new IllegalArgumentException( "need 12 bytes" );
|
||||
ByteBuffer bb = ByteBuffer.wrap( b );
|
||||
_time = bb.getInt();
|
||||
_machine = bb.getInt();
|
||||
_inc = bb.getInt();
|
||||
_new = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ObjectId
|
||||
* @param time time in seconds
|
||||
* @param machine machine ID
|
||||
* @param inc incremental value
|
||||
*/
|
||||
public ObjectId( int time , int machine , int inc ){
|
||||
_time = time;
|
||||
_machine = machine;
|
||||
_inc = inc;
|
||||
_new = false;
|
||||
}
|
||||
|
||||
/** Create a new object id.
|
||||
*/
|
||||
public ObjectId(){
|
||||
_time = (int) (System.currentTimeMillis() / 1000);
|
||||
_machine = _genmachine;
|
||||
_inc = _nextInc.getAndIncrement();
|
||||
_new = true;
|
||||
}
|
||||
|
||||
public int hashCode(){
|
||||
int x = _time;
|
||||
x += ( _machine * 111 );
|
||||
x += ( _inc * 17 );
|
||||
return x;
|
||||
}
|
||||
|
||||
public boolean equals( Object o ){
|
||||
|
||||
if ( this == o )
|
||||
return true;
|
||||
|
||||
ObjectId other = massageToObjectId( o );
|
||||
if ( other == null )
|
||||
return false;
|
||||
|
||||
return
|
||||
_time == other._time &&
|
||||
_machine == other._machine &&
|
||||
_inc == other._inc;
|
||||
}
|
||||
|
||||
public String toStringBabble(){
|
||||
return babbleToMongod( toStringMongod() );
|
||||
}
|
||||
|
||||
public String toStringMongod(){
|
||||
byte b[] = toByteArray();
|
||||
|
||||
StringBuilder buf = new StringBuilder(24);
|
||||
|
||||
for ( int i=0; i<b.length; i++ ){
|
||||
int x = b[i] & 0xFF;
|
||||
String s = Integer.toHexString( x );
|
||||
if ( s.length() == 1 )
|
||||
buf.append( "0" );
|
||||
buf.append( s );
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public byte[] toByteArray(){
|
||||
byte b[] = new byte[12];
|
||||
ByteBuffer bb = ByteBuffer.wrap( b );
|
||||
// by default BB is big endian like we need
|
||||
bb.putInt( _time );
|
||||
bb.putInt( _machine );
|
||||
bb.putInt( _inc );
|
||||
return b;
|
||||
}
|
||||
|
||||
static String _pos( String s , int p ){
|
||||
return s.substring( p * 2 , ( p * 2 ) + 2 );
|
||||
}
|
||||
|
||||
public static String babbleToMongod( String b ){
|
||||
if ( ! isValid( b ) )
|
||||
throw new IllegalArgumentException( "invalid object id: " + b );
|
||||
|
||||
StringBuilder buf = new StringBuilder( 24 );
|
||||
for ( int i=7; i>=0; i-- )
|
||||
buf.append( _pos( b , i ) );
|
||||
for ( int i=11; i>=8; i-- )
|
||||
buf.append( _pos( b , i ) );
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return toStringMongod();
|
||||
}
|
||||
|
||||
int _compareUnsigned( int i , int j ){
|
||||
long li = 0xFFFFFFFFL;
|
||||
li = i & li;
|
||||
long lj = 0xFFFFFFFFL;
|
||||
lj = j & lj;
|
||||
long diff = li - lj;
|
||||
if (diff < Integer.MIN_VALUE)
|
||||
return Integer.MIN_VALUE;
|
||||
if (diff > Integer.MAX_VALUE)
|
||||
return Integer.MAX_VALUE;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
public int compareTo( ObjectId id ){
|
||||
if ( id == null )
|
||||
return -1;
|
||||
|
||||
int x = _compareUnsigned( _time , id._time );
|
||||
if ( x != 0 )
|
||||
return x;
|
||||
|
||||
x = _compareUnsigned( _machine , id._machine );
|
||||
if ( x != 0 )
|
||||
return x;
|
||||
|
||||
return _compareUnsigned( _inc , id._inc );
|
||||
}
|
||||
|
||||
public int getMachine(){
|
||||
return _machine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time of this ID, in milliseconds
|
||||
*/
|
||||
public long getTime(){
|
||||
return _time * 1000L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time of this ID, in seconds
|
||||
*/
|
||||
public int getTimeSecond(){
|
||||
return _time;
|
||||
}
|
||||
|
||||
public int getInc(){
|
||||
return _inc;
|
||||
}
|
||||
|
||||
public int _time(){
|
||||
return _time;
|
||||
}
|
||||
public int _machine(){
|
||||
return _machine;
|
||||
}
|
||||
public int _inc(){
|
||||
return _inc;
|
||||
}
|
||||
|
||||
public boolean isNew(){
|
||||
return _new;
|
||||
}
|
||||
|
||||
public void notNew(){
|
||||
_new = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the generated machine ID, identifying the machine / process / class loader
|
||||
*/
|
||||
public static int getGenMachineId() {
|
||||
return _genmachine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current value of the auto increment
|
||||
*/
|
||||
public static int getCurrentInc() {
|
||||
return _nextInc.get();
|
||||
}
|
||||
|
||||
final int _time;
|
||||
final int _machine;
|
||||
final int _inc;
|
||||
|
||||
boolean _new;
|
||||
|
||||
public static int _flip( int x ){
|
||||
int z = 0;
|
||||
z |= ( ( x << 24 ) & 0xFF000000 );
|
||||
z |= ( ( x << 8 ) & 0x00FF0000 );
|
||||
z |= ( ( x >> 8 ) & 0x0000FF00 );
|
||||
z |= ( ( x >> 24 ) & 0x000000FF );
|
||||
return z;
|
||||
}
|
||||
|
||||
private static AtomicInteger _nextInc = new AtomicInteger( (new java.util.Random()).nextInt() );
|
||||
|
||||
private static final int _genmachine;
|
||||
static {
|
||||
|
||||
try {
|
||||
// build a 2-byte machine piece based on NICs info
|
||||
int machinePiece;
|
||||
{
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
|
||||
while ( e.hasMoreElements() ){
|
||||
NetworkInterface ni = e.nextElement();
|
||||
sb.append( ni.toString() );
|
||||
}
|
||||
machinePiece = sb.toString().hashCode() << 16;
|
||||
} catch (Throwable e) {
|
||||
// exception sometimes happens with IBM JVM, use random
|
||||
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
||||
machinePiece = (new Random().nextInt()) << 16;
|
||||
}
|
||||
LOGGER.fine( "machine piece post: " + Integer.toHexString( machinePiece ) );
|
||||
}
|
||||
|
||||
// add a 2 byte process piece. It must represent not only the JVM but the class loader.
|
||||
// Since static var belong to class loader there could be collisions otherwise
|
||||
final int processPiece;
|
||||
{
|
||||
int processId = new java.util.Random().nextInt();
|
||||
try {
|
||||
processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
|
||||
}
|
||||
catch ( Throwable t ){
|
||||
}
|
||||
|
||||
ClassLoader loader = ObjectId.class.getClassLoader();
|
||||
int loaderId = loader != null ? System.identityHashCode(loader) : 0;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(Integer.toHexString(processId));
|
||||
sb.append(Integer.toHexString(loaderId));
|
||||
processPiece = sb.toString().hashCode() & 0xFFFF;
|
||||
LOGGER.fine( "process piece: " + Integer.toHexString( processPiece ) );
|
||||
}
|
||||
|
||||
_genmachine = machinePiece | processPiece;
|
||||
LOGGER.fine( "machine : " + Integer.toHexString( _genmachine ) );
|
||||
}
|
||||
catch ( Exception e ){
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
74
src/com/massivecraft/mcore4/lib/bson/types/Symbol.java
Normal file
74
src/com/massivecraft/mcore4/lib/bson/types/Symbol.java
Normal file
@@ -0,0 +1,74 @@
|
||||
// Symbol.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009 10gen 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.mcore4.lib.bson.types;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Class to hold a BSON symbol object, which is an interned string in Ruby
|
||||
*/
|
||||
public class Symbol implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1326269319883146072L;
|
||||
|
||||
public Symbol(String s) {
|
||||
_symbol = s;
|
||||
}
|
||||
|
||||
public String getSymbol(){
|
||||
return _symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will compare equal to a String that is equal to the String that this holds
|
||||
* @param o
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null) return false;
|
||||
|
||||
String otherSymbol;
|
||||
if (o instanceof Symbol) {
|
||||
otherSymbol = ((Symbol) o)._symbol;
|
||||
}
|
||||
else if (o instanceof String) {
|
||||
otherSymbol = (String) o;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_symbol != null ? !_symbol.equals(otherSymbol) : otherSymbol != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _symbol != null ? _symbol.hashCode() : 0;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return _symbol;
|
||||
}
|
||||
|
||||
private final String _symbol;
|
||||
}
|
||||
3
src/com/massivecraft/mcore4/lib/bson/types/package.html
Normal file
3
src/com/massivecraft/mcore4/lib/bson/types/package.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
<p>Contains classes implementing various BSON types.</p>
|
||||
</body>
|
||||
@@ -0,0 +1,631 @@
|
||||
/**
|
||||
* Copyright 2008 Atlassian Pty Ltd
|
||||
*
|
||||
* 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.mcore4.lib.bson.util;
|
||||
|
||||
import static com.massivecraft.mcore4.lib.bson.util.Assertions.notNull;
|
||||
import static java.util.Collections.unmodifiableCollection;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.util.annotations.GuardedBy;
|
||||
import com.massivecraft.mcore4.lib.bson.util.annotations.ThreadSafe;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Abstract base class for COW {@link Map} implementations that delegate to an
|
||||
* internal map.
|
||||
*
|
||||
* @param <K> The key type
|
||||
* @param <V> The value type
|
||||
* @param <M> the internal {@link Map} or extension for things like sorted and
|
||||
* navigable maps.
|
||||
*/
|
||||
@ThreadSafe
|
||||
abstract class AbstractCopyOnWriteMap<K, V, M extends Map<K, V>> implements ConcurrentMap<K, V>, Serializable {
|
||||
private static final long serialVersionUID = 4508989182041753878L;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private volatile M delegate;
|
||||
|
||||
// import edu.umd.cs.findbugs.annotations.@SuppressWarnings
|
||||
private final transient Lock lock = new ReentrantLock();
|
||||
|
||||
// private final transient EntrySet entrySet = new EntrySet();
|
||||
// private final transient KeySet keySet = new KeySet();
|
||||
// private final transient Values values = new Values();
|
||||
// private final View.Type viewType;
|
||||
private final View<K, V> view;
|
||||
|
||||
/**
|
||||
* Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
|
||||
* initialize the values.
|
||||
*
|
||||
* @param map the initial map to initialize with
|
||||
* @param viewType for writable or read-only key, value and entrySet views
|
||||
*/
|
||||
protected <N extends Map<? extends K, ? extends V>> AbstractCopyOnWriteMap(final N map, final View.Type viewType) {
|
||||
this.delegate = notNull("delegate", copy(notNull("map", map)));
|
||||
this.view = notNull("viewType", viewType).get(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy function, implemented by sub-classes.
|
||||
*
|
||||
* @param <N> the map to copy and return.
|
||||
* @param map the initial values of the newly created map.
|
||||
* @return a new map. Will never be modified after construction.
|
||||
*/
|
||||
@GuardedBy("lock")
|
||||
abstract <N extends Map<? extends K, ? extends V>> M copy(N map);
|
||||
|
||||
//
|
||||
// mutable operations
|
||||
//
|
||||
|
||||
public final void clear() {
|
||||
lock.lock();
|
||||
try {
|
||||
set(copy(Collections.<K, V> emptyMap()));
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public final V remove(final Object key) {
|
||||
lock.lock();
|
||||
try {
|
||||
// short circuit if key doesn't exist
|
||||
if (!delegate.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.remove(key);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(final Object key, final Object value) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (delegate.containsKey(key) && equals(value, delegate.get(key))) {
|
||||
final M map = copy();
|
||||
map.remove(key);
|
||||
set(map);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean replace(final K key, final V oldValue, final V newValue) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (!delegate.containsKey(key) || !equals(oldValue, delegate.get(key))) {
|
||||
return false;
|
||||
}
|
||||
final M map = copy();
|
||||
map.put(key, newValue);
|
||||
set(map);
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public V replace(final K key, final V value) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (!delegate.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.put(key, value);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public final V put(final K key, final V value) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.put(key, value);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public V putIfAbsent(final K key, final V value) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (!delegate.containsKey(key)) {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.put(key, value);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
}
|
||||
return delegate.get(key);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public final void putAll(final Map<? extends K, ? extends V> t) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
map.putAll(t);
|
||||
set(map);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected M copy() {
|
||||
lock.lock();
|
||||
try {
|
||||
return copy(delegate);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("lock")
|
||||
protected void set(final M map) {
|
||||
delegate = map;
|
||||
}
|
||||
|
||||
//
|
||||
// Collection views
|
||||
//
|
||||
|
||||
public final Set<Map.Entry<K, V>> entrySet() {
|
||||
return view.entrySet();
|
||||
}
|
||||
|
||||
public final Set<K> keySet() {
|
||||
return view.keySet();
|
||||
}
|
||||
|
||||
public final Collection<V> values() {
|
||||
return view.values();
|
||||
}
|
||||
|
||||
//
|
||||
// delegate operations
|
||||
//
|
||||
|
||||
public final boolean containsKey(final Object key) {
|
||||
return delegate.containsKey(key);
|
||||
}
|
||||
|
||||
public final boolean containsValue(final Object value) {
|
||||
return delegate.containsValue(value);
|
||||
}
|
||||
|
||||
public final V get(final Object key) {
|
||||
return delegate.get(key);
|
||||
}
|
||||
|
||||
public final boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
}
|
||||
|
||||
public final int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(final Object o) {
|
||||
return delegate.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
protected final M getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
|
||||
//
|
||||
// inner classes
|
||||
//
|
||||
|
||||
private class KeySet extends CollectionView<K> implements Set<K> {
|
||||
|
||||
@Override
|
||||
Collection<K> getDelegate() {
|
||||
return delegate.keySet();
|
||||
}
|
||||
|
||||
//
|
||||
// mutable operations
|
||||
//
|
||||
|
||||
public void clear() {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
map.keySet().clear();
|
||||
set(map);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(final Object o) {
|
||||
return AbstractCopyOnWriteMap.this.remove(o) != null;
|
||||
}
|
||||
|
||||
public boolean removeAll(final Collection<?> c) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.keySet().removeAll(c);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean retainAll(final Collection<?> c) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.keySet().retainAll(c);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class Values extends CollectionView<V> {
|
||||
|
||||
@Override
|
||||
Collection<V> getDelegate() {
|
||||
return delegate.values();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
map.values().clear();
|
||||
set(map);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(final Object o) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (!contains(o)) {
|
||||
return false;
|
||||
}
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.values().remove(o);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeAll(final Collection<?> c) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.values().removeAll(c);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean retainAll(final Collection<?> c) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.values().retainAll(c);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class EntrySet extends CollectionView<Entry<K, V>> implements Set<Map.Entry<K, V>> {
|
||||
|
||||
@Override
|
||||
Collection<java.util.Map.Entry<K, V>> getDelegate() {
|
||||
return delegate.entrySet();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
map.entrySet().clear();
|
||||
set(map);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean remove(final Object o) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (!contains(o)) {
|
||||
return false;
|
||||
}
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.entrySet().remove(o);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeAll(final Collection<?> c) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.entrySet().removeAll(c);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean retainAll(final Collection<?> c) {
|
||||
lock.lock();
|
||||
try {
|
||||
final M map = copy();
|
||||
try {
|
||||
return map.entrySet().retainAll(c);
|
||||
} finally {
|
||||
set(map);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class UnmodifiableIterator<T> implements Iterator<T> {
|
||||
private final Iterator<T> delegate;
|
||||
|
||||
public UnmodifiableIterator(final Iterator<T> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return delegate.hasNext();
|
||||
}
|
||||
|
||||
public T next() {
|
||||
return delegate.next();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
protected static abstract class CollectionView<E> implements Collection<E> {
|
||||
|
||||
abstract Collection<E> getDelegate();
|
||||
|
||||
//
|
||||
// delegate operations
|
||||
//
|
||||
|
||||
public final boolean contains(final Object o) {
|
||||
return getDelegate().contains(o);
|
||||
}
|
||||
|
||||
public final boolean containsAll(final Collection<?> c) {
|
||||
return getDelegate().containsAll(c);
|
||||
}
|
||||
|
||||
public final Iterator<E> iterator() {
|
||||
return new UnmodifiableIterator<E>(getDelegate().iterator());
|
||||
}
|
||||
|
||||
public final boolean isEmpty() {
|
||||
return getDelegate().isEmpty();
|
||||
}
|
||||
|
||||
public final int size() {
|
||||
return getDelegate().size();
|
||||
}
|
||||
|
||||
public final Object[] toArray() {
|
||||
return getDelegate().toArray();
|
||||
}
|
||||
|
||||
public final <T> T[] toArray(final T[] a) {
|
||||
return getDelegate().toArray(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getDelegate().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
return getDelegate().equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDelegate().toString();
|
||||
}
|
||||
|
||||
//
|
||||
// unsupported operations
|
||||
//
|
||||
|
||||
public final boolean add(final E o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public final boolean addAll(final Collection<? extends E> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean equals(final Object o1, final Object o2) {
|
||||
if (o1 == null) {
|
||||
return o2 == null;
|
||||
}
|
||||
return o1.equals(o2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides access to the views of the underlying key, value and entry
|
||||
* collections.
|
||||
*/
|
||||
public static abstract class View<K, V> {
|
||||
View() {}
|
||||
|
||||
abstract Set<K> keySet();
|
||||
|
||||
abstract Set<Entry<K, V>> entrySet();
|
||||
|
||||
abstract Collection<V> values();
|
||||
|
||||
/**
|
||||
* The different types of {@link View} available
|
||||
*/
|
||||
public enum Type {
|
||||
STABLE {
|
||||
@Override
|
||||
<K, V, M extends Map<K, V>> View<K, V> get(final AbstractCopyOnWriteMap<K, V, M> host) {
|
||||
return host.new Immutable();
|
||||
}
|
||||
},
|
||||
LIVE {
|
||||
@Override
|
||||
<K, V, M extends Map<K, V>> View<K, V> get(final AbstractCopyOnWriteMap<K, V, M> host) {
|
||||
return host.new Mutable();
|
||||
}
|
||||
};
|
||||
abstract <K, V, M extends Map<K, V>> View<K, V> get(AbstractCopyOnWriteMap<K, V, M> host);
|
||||
}
|
||||
}
|
||||
|
||||
final class Immutable extends View<K, V> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4158727180429303818L;
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return unmodifiableSet(delegate.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return unmodifiableSet(delegate.entrySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return unmodifiableCollection(delegate.values());
|
||||
}
|
||||
}
|
||||
|
||||
final class Mutable extends View<K, V> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1624520291194797634L;
|
||||
|
||||
private final transient KeySet keySet = new KeySet();
|
||||
private final transient EntrySet entrySet = new EntrySet();
|
||||
private final transient Values values = new Values();
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
return keySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
return entrySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/com/massivecraft/mcore4/lib/bson/util/Assertions.java
Normal file
48
src/com/massivecraft/mcore4/lib/bson/util/Assertions.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright 2008 Atlassian Pty Ltd
|
||||
*
|
||||
* 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.mcore4.lib.bson.util;
|
||||
|
||||
/**
|
||||
* Design by contract assertions.
|
||||
*/
|
||||
public class Assertions {
|
||||
public static <T> T notNull(final String name, final T notNull) throws IllegalArgumentException {
|
||||
if (notNull == null) {
|
||||
throw new NullArgumentException(name);
|
||||
}
|
||||
return notNull;
|
||||
}
|
||||
|
||||
public static void isTrue(final String name, final boolean check) throws IllegalArgumentException {
|
||||
if (!check) {
|
||||
throw new IllegalArgumentException(name);
|
||||
}
|
||||
}
|
||||
|
||||
// /CLOVER:OFF
|
||||
private Assertions() {}
|
||||
|
||||
// /CLOVER:ON
|
||||
|
||||
static class NullArgumentException extends IllegalArgumentException {
|
||||
private static final long serialVersionUID = 6178592463723624585L;
|
||||
|
||||
NullArgumentException(final String name) {
|
||||
super(name + " should not be null!");
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/com/massivecraft/mcore4/lib/bson/util/ClassAncestry.java
Normal file
72
src/com/massivecraft/mcore4/lib/bson/util/ClassAncestry.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package com.massivecraft.mcore4.lib.bson.util;
|
||||
|
||||
import static com.massivecraft.mcore4.lib.bson.util.CopyOnWriteMap.newHashMap;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
class ClassAncestry {
|
||||
|
||||
/**
|
||||
* getAncestry
|
||||
*
|
||||
* Walks superclass and interface graph, superclasses first, then
|
||||
* interfaces, to compute an ancestry list. Supertypes are visited left to
|
||||
* right. Duplicates are removed such that no Class will appear in the list
|
||||
* before one of its subtypes.
|
||||
*
|
||||
* Does not need to be synchronized, races are harmless as the Class graph
|
||||
* does not change at runtime.
|
||||
*/
|
||||
public static <T> List<Class<?>> getAncestry(Class<T> c) {
|
||||
final ConcurrentMap<Class<?>, List<Class<?>>> cache = getClassAncestryCache();
|
||||
while (true) {
|
||||
List<Class<?>> cachedResult = cache.get(c);
|
||||
if (cachedResult != null) {
|
||||
return cachedResult;
|
||||
}
|
||||
cache.putIfAbsent(c, computeAncestry(c));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* computeAncestry, starting with children and going back to parents
|
||||
*/
|
||||
private static List<Class<?>> computeAncestry(Class<?> c) {
|
||||
final List<Class<?>> result = new ArrayList<Class<?>>();
|
||||
result.add(Object.class);
|
||||
computeAncestry(c, result);
|
||||
Collections.reverse(result);
|
||||
return unmodifiableList(new ArrayList<Class<?>>(result));
|
||||
}
|
||||
|
||||
private static <T> void computeAncestry(Class<T> c, List<Class<?>> result) {
|
||||
if ((c == null) || (c == Object.class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// first interfaces (looks backwards but is not)
|
||||
Class<?>[] interfaces = c.getInterfaces();
|
||||
for (int i = interfaces.length - 1; i >= 0; i--) {
|
||||
computeAncestry(interfaces[i], result);
|
||||
}
|
||||
|
||||
// next superclass
|
||||
computeAncestry(c.getSuperclass(), result);
|
||||
|
||||
if (!result.contains(c))
|
||||
result.add(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* classAncestryCache
|
||||
*/
|
||||
private static ConcurrentMap<Class<?>, List<Class<?>>> getClassAncestryCache() {
|
||||
return (_ancestryCache);
|
||||
}
|
||||
|
||||
private static final ConcurrentMap<Class<?>, List<Class<?>>> _ancestryCache = newHashMap();
|
||||
}
|
||||
100
src/com/massivecraft/mcore4/lib/bson/util/ClassMap.java
Normal file
100
src/com/massivecraft/mcore4/lib/bson/util/ClassMap.java
Normal file
@@ -0,0 +1,100 @@
|
||||
// ClassMap.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Maps Class objects to values. A ClassMap is different from a regular Map in
|
||||
* that get(c) does not only look to see if 'c' is a key in the Map, but also
|
||||
* walks the up superclass and interface graph of 'c' to find matches. Derived
|
||||
* matches of this sort are then "cached" in the registry so that matches are
|
||||
* faster on future gets.
|
||||
*
|
||||
* This is a very useful class for Class based registries.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ClassMap<String> m = new ClassMap<String>(); m.put(Animal.class, "Animal");
|
||||
* m.put(Fox.class, "Fox"); m.Fox.class) --> "Fox" m.get(Dog.class) --> "Animal"
|
||||
*
|
||||
* (assuming Dog.class < Animal.class)
|
||||
*/
|
||||
public class ClassMap<T> {
|
||||
/**
|
||||
* Walks superclass and interface graph, superclasses first, then
|
||||
* interfaces, to compute an ancestry list. Supertypes are visited left to
|
||||
* right. Duplicates are removed such that no Class will appear in the list
|
||||
* before one of its subtypes.
|
||||
*/
|
||||
public static <T> List<Class<?>> getAncestry(Class<T> c) {
|
||||
return ClassAncestry.getAncestry(c);
|
||||
}
|
||||
|
||||
private final class ComputeFunction implements Function<Class<?>, T> {
|
||||
@Override
|
||||
public T apply(Class<?> a) {
|
||||
for (Class<?> cls : getAncestry(a)) {
|
||||
T result = map.get(cls);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private final Map<Class<?>, T> map = CopyOnWriteMap.newHashMap();
|
||||
private final Map<Class<?>, T> cache = ComputingMap.create(new ComputeFunction());
|
||||
|
||||
|
||||
public T get(Object key) {
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
public T put(Class<?> key, T value) {
|
||||
try {
|
||||
return map.put(key, value);
|
||||
} finally {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public T remove(Object key) {
|
||||
try {
|
||||
return map.remove(key);
|
||||
} finally {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
}
|
||||
109
src/com/massivecraft/mcore4/lib/bson/util/ComputingMap.java
Normal file
109
src/com/massivecraft/mcore4/lib/bson/util/ComputingMap.java
Normal file
@@ -0,0 +1,109 @@
|
||||
package com.massivecraft.mcore4.lib.bson.util;
|
||||
|
||||
import static com.massivecraft.mcore4.lib.bson.util.Assertions.notNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
final class ComputingMap<K, V> implements Map<K, V>, Function<K, V> {
|
||||
|
||||
public static <K, V> Map<K, V> create(Function<K, V> function) {
|
||||
return new ComputingMap<K, V>(CopyOnWriteMap.<K, V> newHashMap(), function);
|
||||
}
|
||||
|
||||
private final ConcurrentMap<K, V> map;
|
||||
private final Function<K, V> function;
|
||||
|
||||
ComputingMap(ConcurrentMap<K, V> map, Function<K, V> function) {
|
||||
this.map = notNull("map", map);
|
||||
this.function = notNull("function", function);
|
||||
}
|
||||
|
||||
public V get(Object key) {
|
||||
while (true) {
|
||||
V v = map.get(key);
|
||||
if (v != null)
|
||||
return v;
|
||||
@SuppressWarnings("unchecked")
|
||||
K k = (K) key;
|
||||
V value = function.apply(k);
|
||||
if (value == null)
|
||||
return null;
|
||||
map.putIfAbsent(k, value);
|
||||
}
|
||||
}
|
||||
|
||||
public V apply(K k) {
|
||||
return get(k);
|
||||
}
|
||||
|
||||
public V putIfAbsent(K key, V value) {
|
||||
return map.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
public boolean remove(Object key, Object value) {
|
||||
return map.remove(key, value);
|
||||
}
|
||||
|
||||
public boolean replace(K key, V oldValue, V newValue) {
|
||||
return map.replace(key, oldValue, newValue);
|
||||
}
|
||||
|
||||
public V replace(K key, V value) {
|
||||
return map.replace(key, value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
public V put(K key, V value) {
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
public V remove(Object key) {
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
map.putAll(m);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public Set<K> keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
public Collection<V> values() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return map.equals(o);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return map.hashCode();
|
||||
}
|
||||
}
|
||||
273
src/com/massivecraft/mcore4/lib/bson/util/CopyOnWriteMap.java
Normal file
273
src/com/massivecraft/mcore4/lib/bson/util/CopyOnWriteMap.java
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* Copyright 2008 Atlassian Pty Ltd
|
||||
*
|
||||
* 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.mcore4.lib.bson.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
|
||||
import com.massivecraft.mcore4.lib.bson.util.AbstractCopyOnWriteMap.View.Type;
|
||||
import com.massivecraft.mcore4.lib.bson.util.annotations.GuardedBy;
|
||||
import com.massivecraft.mcore4.lib.bson.util.annotations.ThreadSafe;
|
||||
|
||||
/**
|
||||
* A thread-safe variant of {@link Map} in which all mutative operations (the
|
||||
* "destructive" operations described by {@link Map} put, remove and so on) are
|
||||
* implemented by making a fresh copy of the underlying map.
|
||||
* <p>
|
||||
* This is ordinarily too costly, but may be <em>more</em> efficient than
|
||||
* alternatives when traversal operations vastly out-number mutations, and is
|
||||
* useful when you cannot or don't want to synchronize traversals, yet need to
|
||||
* preclude interference among concurrent threads. The "snapshot" style
|
||||
* iterators on the collections returned by {@link #entrySet()},
|
||||
* {@link #keySet()} and {@link #values()} use a reference to the internal map
|
||||
* at the point that the iterator was created. This map never changes during the
|
||||
* lifetime of the iterator, so interference is impossible and the iterator is
|
||||
* guaranteed not to throw <tt>ConcurrentModificationException</tt>. The
|
||||
* iterators will not reflect additions, removals, or changes to the list since
|
||||
* the iterator was created. Removing elements via these iterators is not
|
||||
* supported. The mutable operations on these collections (remove, retain etc.)
|
||||
* are supported but as with the {@link Map} interface, add and addAll are not
|
||||
* and throw {@link UnsupportedOperationException}.
|
||||
* <p>
|
||||
* The actual copy is performed by an abstract {@link #copy(Map)} method. The
|
||||
* method is responsible for the underlying Map implementation (for instance a
|
||||
* {@link HashMap}, {@link TreeMap}, {@link LinkedHashMap} etc.) and therefore
|
||||
* the semantics of what this map will cope with as far as null keys and values,
|
||||
* iteration ordering etc. See the note below about suitable candidates for
|
||||
* underlying Map implementations
|
||||
* <p>
|
||||
* There are supplied implementations for the common j.u.c {@link Map}
|
||||
* implementations via the {@link CopyOnWriteMap} static {@link Builder}.
|
||||
* <p>
|
||||
* Collection views of the keys, values and entries are optionally
|
||||
* {@link View.Type.LIVE live} or {@link View.Type.STABLE stable}. Live views
|
||||
* are modifiable will cause a copy if a modifying method is called on them.
|
||||
* Methods on these will reflect the current state of the collection, although
|
||||
* iterators will be snapshot style. If the collection views are stable they are
|
||||
* unmodifiable, and will be a snapshot of the state of the map at the time the
|
||||
* collection was asked for.
|
||||
* <p>
|
||||
* <strong>Please note</strong> that the thread-safety guarantees are limited to
|
||||
* the thread-safety of the non-mutative (non-destructive) operations of the
|
||||
* underlying map implementation. For instance some implementations such as
|
||||
* {@link WeakHashMap} and {@link LinkedHashMap} with access ordering are
|
||||
* actually structurally modified by the {@link #get(Object)} method and are
|
||||
* therefore not suitable candidates as delegates for this class.
|
||||
*
|
||||
* @param <K> the key type
|
||||
* @param <V> the value type
|
||||
* @author Jed Wesley-Smith
|
||||
*/
|
||||
@ThreadSafe
|
||||
abstract class CopyOnWriteMap<K, V> extends AbstractCopyOnWriteMap<K, V, Map<K, V>> {
|
||||
private static final long serialVersionUID = 7935514534647505917L;
|
||||
|
||||
/**
|
||||
* Get a {@link Builder} for a {@link CopyOnWriteMap} instance.
|
||||
*
|
||||
* @param <K> key type
|
||||
* @param <V> value type
|
||||
* @return a fresh builder
|
||||
*/
|
||||
public static <K, V> Builder<K, V> builder() {
|
||||
return new Builder<K, V>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link CopyOnWriteMap} and specify all the options.
|
||||
*
|
||||
* @param <K> key type
|
||||
* @param <V> value type
|
||||
*/
|
||||
public static class Builder<K, V> {
|
||||
private View.Type viewType = View.Type.STABLE;
|
||||
private final Map<K, V> initialValues = new HashMap<K, V>();
|
||||
|
||||
Builder() {}
|
||||
|
||||
/**
|
||||
* Views are stable (fixed in time) and unmodifiable.
|
||||
*/
|
||||
public Builder<K, V> stableViews() {
|
||||
viewType = View.Type.STABLE;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views are live (reflecting concurrent updates) and mutator methods
|
||||
* are supported.
|
||||
*/
|
||||
public Builder<K, V> addAll(final Map<? extends K, ? extends V> values) {
|
||||
initialValues.putAll(values);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Views are live (reflecting concurrent updates) and mutator methods
|
||||
* are supported.
|
||||
*/
|
||||
public Builder<K, V> liveViews() {
|
||||
viewType = View.Type.LIVE;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CopyOnWriteMap<K, V> newHashMap() {
|
||||
return new Hash<K, V>(initialValues, viewType);
|
||||
}
|
||||
|
||||
public CopyOnWriteMap<K, V> newLinkedMap() {
|
||||
return new Linked<K, V>(initialValues, viewType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}.
|
||||
* <p>
|
||||
* This map has {@link View.Type.STABLE stable} views.
|
||||
*/
|
||||
public static <K, V> CopyOnWriteMap<K, V> newHashMap() {
|
||||
final Builder<K, V> builder = builder();
|
||||
return builder.newHashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}
|
||||
* using the supplied map as the initial values.
|
||||
* <p>
|
||||
* This map has {@link View.Type.STABLE stable} views.
|
||||
*/
|
||||
public static <K, V> CopyOnWriteMap<K, V> newHashMap(final Map<? extends K, ? extends V> map) {
|
||||
final Builder<K, V> builder = builder();
|
||||
return builder.addAll(map).newHashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link CopyOnWriteMap} with an underlying
|
||||
* {@link LinkedHashMap}. Iterators for this map will be return elements in
|
||||
* insertion order.
|
||||
* <p>
|
||||
* This map has {@link View.Type.STABLE stable} views.
|
||||
*/
|
||||
public static <K, V> CopyOnWriteMap<K, V> newLinkedMap() {
|
||||
final Builder<K, V> builder = builder();
|
||||
return builder.newLinkedMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link CopyOnWriteMap} with an underlying
|
||||
* {@link LinkedHashMap} using the supplied map as the initial values.
|
||||
* Iterators for this map will be return elements in insertion order.
|
||||
* <p>
|
||||
* This map has {@link View.Type.STABLE stable} views.
|
||||
*/
|
||||
public static <K, V> CopyOnWriteMap<K, V> newLinkedMap(final Map<? extends K, ? extends V> map) {
|
||||
final Builder<K, V> builder = builder();
|
||||
return builder.addAll(map).newLinkedMap();
|
||||
}
|
||||
|
||||
//
|
||||
// constructors
|
||||
//
|
||||
|
||||
/**
|
||||
* Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
|
||||
* initialize the values.
|
||||
*
|
||||
* @param map the initial map to initialize with
|
||||
* @deprecated since 0.0.12 use the versions that explicitly specify
|
||||
* View.Type
|
||||
*/
|
||||
@Deprecated
|
||||
protected CopyOnWriteMap(final Map<? extends K, ? extends V> map) {
|
||||
this(map, View.Type.LIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new empty {@link CopyOnWriteMap}.
|
||||
*
|
||||
* @deprecated since 0.0.12 use the versions that explicitly specify
|
||||
* View.Type
|
||||
*/
|
||||
@Deprecated
|
||||
protected CopyOnWriteMap() {
|
||||
this(Collections.<K, V> emptyMap(), View.Type.LIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
|
||||
* initialize the values. This map may be optionally modified using any of
|
||||
* the key, entry or value views
|
||||
*
|
||||
* @param map the initial map to initialize with
|
||||
*/
|
||||
protected CopyOnWriteMap(final Map<? extends K, ? extends V> map, final View.Type viewType) {
|
||||
super(map, viewType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new empty {@link CopyOnWriteMap}. This map may be optionally
|
||||
* modified using any of the key, entry or value views
|
||||
*/
|
||||
protected CopyOnWriteMap(final View.Type viewType) {
|
||||
super(Collections.<K, V> emptyMap(), viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@GuardedBy("internal-lock")
|
||||
protected abstract <N extends Map<? extends K, ? extends V>> Map<K, V> copy(N map);
|
||||
|
||||
//
|
||||
// inner classes
|
||||
//
|
||||
|
||||
/**
|
||||
* Uses {@link HashMap} instances as its internal storage.
|
||||
*/
|
||||
static class Hash<K, V> extends CopyOnWriteMap<K, V> {
|
||||
private static final long serialVersionUID = 5221824943734164497L;
|
||||
|
||||
Hash(final Map<? extends K, ? extends V> map, final Type viewType) {
|
||||
super(map, viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
|
||||
return new HashMap<K, V>(map);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses {@link LinkedHashMap} instances as its internal storage.
|
||||
*/
|
||||
static class Linked<K, V> extends CopyOnWriteMap<K, V> {
|
||||
private static final long serialVersionUID = -8659999465009072124L;
|
||||
|
||||
Linked(final Map<? extends K, ? extends V> map, final Type viewType) {
|
||||
super(map, viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
|
||||
return new LinkedHashMap<K, V>(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
5
src/com/massivecraft/mcore4/lib/bson/util/Function.java
Normal file
5
src/com/massivecraft/mcore4/lib/bson/util/Function.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.massivecraft.mcore4.lib.bson.util;
|
||||
|
||||
interface Function<A, B> {
|
||||
B apply(A a);
|
||||
}
|
||||
58
src/com/massivecraft/mcore4/lib/bson/util/SimplePool.java
Normal file
58
src/com/massivecraft/mcore4/lib/bson/util/SimplePool.java
Normal file
@@ -0,0 +1,58 @@
|
||||
// SimplePool.java
|
||||
|
||||
/**
|
||||
* Copyright (C) 2008 10gen 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.mcore4.lib.bson.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public abstract class SimplePool<T> {
|
||||
|
||||
public SimplePool( int max ){
|
||||
_max = max;
|
||||
}
|
||||
|
||||
public SimplePool(){
|
||||
_max = 1000;
|
||||
}
|
||||
|
||||
protected abstract T createNew();
|
||||
|
||||
protected boolean ok( T t ){
|
||||
return true;
|
||||
}
|
||||
|
||||
public T get(){
|
||||
T t = _stored.poll();
|
||||
if ( t != null )
|
||||
return t;
|
||||
return createNew();
|
||||
}
|
||||
|
||||
public void done( T t ){
|
||||
if ( ! ok( t ) )
|
||||
return;
|
||||
|
||||
if ( _stored.size() > _max )
|
||||
return;
|
||||
_stored.add( t );
|
||||
}
|
||||
|
||||
final int _max;
|
||||
private Queue<T> _stored = new ConcurrentLinkedQueue<T>();
|
||||
}
|
||||
130
src/com/massivecraft/mcore4/lib/bson/util/StringRangeSet.java
Normal file
130
src/com/massivecraft/mcore4/lib/bson/util/StringRangeSet.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Copyright (C) 2010 10gen 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.mcore4.lib.bson.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class StringRangeSet implements Set<String> {
|
||||
|
||||
private final int size;
|
||||
|
||||
private final static int NUMSTR_LEN = 100;
|
||||
private final static String[] NUMSTRS = new String[100];
|
||||
static {
|
||||
for (int i = 0; i < NUMSTR_LEN; ++i)
|
||||
NUMSTRS[i] = String.valueOf(i);
|
||||
}
|
||||
|
||||
public StringRangeSet(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Iterator<String> iterator() {
|
||||
return new Iterator<String>() {
|
||||
|
||||
int index = 0;
|
||||
|
||||
public boolean hasNext() {
|
||||
return index < size;
|
||||
}
|
||||
|
||||
public String next() {
|
||||
if (index < NUMSTR_LEN)
|
||||
return NUMSTRS[index++];
|
||||
return String.valueOf(index++);
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(String e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends String> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
int t = Integer.parseInt(String.valueOf(o));
|
||||
return t >= 0 && t < size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
for (Object o : c) {
|
||||
if (!contains(o)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
String[] array = new String[size()];
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (i < NUMSTR_LEN) {
|
||||
array[i] = NUMSTRS[i];
|
||||
} else {
|
||||
array[i] = String.valueOf(i);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
||||
* Released under the Creative Commons Attribution License
|
||||
* (http://creativecommons.org/licenses/by/2.5)
|
||||
* Official home: http://www.jcip.net
|
||||
*
|
||||
* Any republication or derived work distributed in source code form
|
||||
* must include this copyright and license notice.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore4.lib.bson.util.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The field or method to which this annotation is applied can only be accessed
|
||||
* when holding a particular lock, which may be a built-in (synchronization) lock,
|
||||
* or may be an explicit java.util.concurrent.Lock.
|
||||
*
|
||||
* The argument determines which lock guards the annotated field or method:
|
||||
* <ul>
|
||||
* <li>
|
||||
* <code>this</code> : The intrinsic lock of the object in whose class the field is defined.
|
||||
* </li>
|
||||
* <li>
|
||||
* <code>class-name.this</code> : For inner classes, it may be necessary to disambiguate 'this';
|
||||
* the <em>class-name.this</em> designation allows you to specify which 'this' reference is intended
|
||||
* </li>
|
||||
* <li>
|
||||
* <code>itself</code> : For reference fields only; the object to which the field refers.
|
||||
* </li>
|
||||
* <li>
|
||||
* <code>field-name</code> : The lock object is referenced by the (instance or static) field
|
||||
* specified by <em>field-name</em>.
|
||||
* </li>
|
||||
* <li>
|
||||
* <code>class-name.field-name</code> : The lock object is reference by the static field specified
|
||||
* by <em>class-name.field-name</em>.
|
||||
* </li>
|
||||
* <li>
|
||||
* <code>method-name()</code> : The lock object is returned by calling the named nil-ary method.
|
||||
* </li>
|
||||
* <li>
|
||||
* <code>class-name.class</code> : The Class object for the specified class should be used as the lock object.
|
||||
* </li>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface GuardedBy {
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
||||
* Released under the Creative Commons Attribution License
|
||||
* (http://creativecommons.org/licenses/by/2.5)
|
||||
* Official home: http://www.jcip.net
|
||||
*
|
||||
* Any republication or derived work distributed in source code form
|
||||
* must include this copyright and license notice.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore4.lib.bson.util.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* The class to which this annotation is applied is immutable. This means that
|
||||
* its state cannot be seen to change by callers, which implies that
|
||||
* <ul>
|
||||
* <li> all public fields are final, </li>
|
||||
* <li> all public final reference fields refer to other immutable objects, and </li>
|
||||
* <li> constructors and methods do not publish references to any internal state
|
||||
* which is potentially mutable by the implementation. </li>
|
||||
* </ul>
|
||||
* Immutable objects may still have internal mutable state for purposes of performance
|
||||
* optimization; some state variables may be lazily computed, so long as they are computed
|
||||
* from immutable state and that callers cannot tell the difference.
|
||||
* <p>
|
||||
* Immutable objects are inherently thread-safe; they may be passed between threads or
|
||||
* published without synchronization.
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Immutable {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
||||
* Released under the Creative Commons Attribution License
|
||||
* (http://creativecommons.org/licenses/by/2.5)
|
||||
* Official home: http://www.jcip.net
|
||||
*
|
||||
* Any republication or derived work distributed in source code form
|
||||
* must include this copyright and license notice.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore4.lib.bson.util.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
/**
|
||||
* The class to which this annotation is applied is not thread-safe.
|
||||
* This annotation primarily exists for clarifying the non-thread-safety of a class
|
||||
* that might otherwise be assumed to be thread-safe, despite the fact that it is a bad
|
||||
* idea to assume a class is thread-safe without good reason.
|
||||
* @see ThreadSafe
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NotThreadSafe {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
||||
* Released under the Creative Commons Attribution License
|
||||
* (http://creativecommons.org/licenses/by/2.5)
|
||||
* Official home: http://www.jcip.net
|
||||
*
|
||||
* Any republication or derived work distributed in source code form
|
||||
* must include this copyright and license notice.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore4.lib.bson.util.annotations;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
|
||||
/**
|
||||
* The class to which this annotation is applied is thread-safe. This means that
|
||||
* no sequences of accesses (reads and writes to public fields, calls to public methods)
|
||||
* may put the object into an invalid state, regardless of the interleaving of those actions
|
||||
* by the runtime, and without requiring any additional synchronization or coordination on the
|
||||
* part of the caller.
|
||||
*/
|
||||
@Documented
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ThreadSafe {
|
||||
}
|
||||
3
src/com/massivecraft/mcore4/lib/bson/util/package.html
Normal file
3
src/com/massivecraft/mcore4/lib/bson/util/package.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
<p>Misc utils used by BSON.</p>
|
||||
</body>
|
||||
129
src/com/massivecraft/mcore4/lib/gson/DefaultDateTypeAdapter.java
Normal file
129
src/com/massivecraft/mcore4/lib/gson/DefaultDateTypeAdapter.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.mcore4.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;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.DefaultDateTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* This type adapter supports three subclasses of date: Date, Timestamp, and
|
||||
* java.sql.Date.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
|
||||
|
||||
// TODO: migrate to streaming adapter
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
113
src/com/massivecraft/mcore4/lib/gson/ExclusionStrategy.java
Normal file
113
src/com/massivecraft/mcore4/lib/gson/ExclusionStrategy.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.ExclusionStrategy;
|
||||
import com.massivecraft.mcore4.lib.gson.FieldAttributes;
|
||||
import com.massivecraft.mcore4.lib.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
158
src/com/massivecraft/mcore4/lib/gson/FieldAttributes.java
Normal file
158
src/com/massivecraft/mcore4/lib/gson/FieldAttributes.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 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 final Field field;
|
||||
|
||||
/**
|
||||
* Constructs a Field Attributes object from the {@code f}.
|
||||
*
|
||||
* @param f the field to pull attributes from
|
||||
*/
|
||||
public FieldAttributes(Field f) {
|
||||
$Gson$Preconditions.checkNotNull(f);
|
||||
this.field = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the declaring class that contains this field
|
||||
*/
|
||||
public Class<?> getDeclaringClass() {
|
||||
return field.getDeclaringClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the field
|
||||
*/
|
||||
public String getName() {
|
||||
return field.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* <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() {
|
||||
return field.getGenericType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 field.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 field.getAnnotation(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() {
|
||||
return Arrays.asList(field.getAnnotations());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (field.getModifiers() & 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 field.isSynthetic();
|
||||
}
|
||||
}
|
||||
170
src/com/massivecraft/mcore4/lib/gson/FieldNamingPolicy.java
Normal file
170
src/com/massivecraft/mcore4/lib/gson/FieldNamingPolicy.java
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.FieldNamingStrategy;
|
||||
|
||||
/**
|
||||
* An enumeration that defines a few standard naming conventions for JSON field names.
|
||||
* This enumeration should be used in conjunction with {@link com.massivecraft.mcore4.lib.gson.GsonBuilder}
|
||||
* to configure a {@link com.massivecraft.mcore4.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 implements FieldNamingStrategy {
|
||||
|
||||
/**
|
||||
* Using this naming policy with Gson will ensure that the field name is
|
||||
* unchanged.
|
||||
*/
|
||||
IDENTITY() {
|
||||
public String translateName(Field f) {
|
||||
return f.getName();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
public String translateName(Field f) {
|
||||
return upperCaseFirstLetter(f.getName());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
public String translateName(Field f) {
|
||||
return upperCaseFirstLetter(separateCamelCase(f.getName(), " "));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
public String translateName(Field f) {
|
||||
return separateCamelCase(f.getName(), "_").toLowerCase();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
public String translateName(Field f) {
|
||||
return separateCamelCase(f.getName(), "-").toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the field name that uses camel-case define word separation into
|
||||
* separate words that are separated by the provided {@code separatorString}.
|
||||
*/
|
||||
private static String separateCamelCase(String name, String separator) {
|
||||
StringBuilder translation = new StringBuilder();
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char character = name.charAt(i);
|
||||
if (Character.isUpperCase(character) && translation.length() != 0) {
|
||||
translation.append(separator);
|
||||
}
|
||||
translation.append(character);
|
||||
}
|
||||
return translation.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the JSON field names begins with an upper case letter.
|
||||
*/
|
||||
private static String upperCaseFirstLetter(String name) {
|
||||
StringBuilder fieldNameBuilder = new StringBuilder();
|
||||
int index = 0;
|
||||
char firstCharacter = name.charAt(index);
|
||||
|
||||
while (index < name.length() - 1) {
|
||||
if (Character.isLetter(firstCharacter)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fieldNameBuilder.append(firstCharacter);
|
||||
firstCharacter = name.charAt(++index);
|
||||
}
|
||||
|
||||
if (index == name.length()) {
|
||||
return fieldNameBuilder.toString();
|
||||
}
|
||||
|
||||
if (!Character.isUpperCase(firstCharacter)) {
|
||||
String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), name, ++index);
|
||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private static String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
|
||||
return (indexOfSubstring < srcString.length())
|
||||
? firstCharacter + srcString.substring(indexOfSubstring)
|
||||
: String.valueOf(firstCharacter);
|
||||
}
|
||||
}
|
||||
@@ -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.mcore4.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);
|
||||
}
|
||||
874
src/com/massivecraft/mcore4/lib/gson/Gson.java
Normal file
874
src/com/massivecraft/mcore4/lib/gson/Gson.java
Normal file
@@ -0,0 +1,874 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.FieldNamingPolicy;
|
||||
import com.massivecraft.mcore4.lib.gson.FieldNamingStrategy;
|
||||
import com.massivecraft.mcore4.lib.gson.Gson;
|
||||
import com.massivecraft.mcore4.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore4.lib.gson.InstanceCreator;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore4.lib.gson.LongSerializationPolicy;
|
||||
import com.massivecraft.mcore4.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.Excluder;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.GsonInternalAccess;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.ArrayTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.BigDecimalTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.BigIntegerTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.CollectionTypeAdapterFactory;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.DateTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.JsonTreeReader;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.JsonTreeWriter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.MapTypeAdapterFactory;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.ObjectTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.ReflectiveTypeAdapterFactory;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.SqlDateTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.TimeTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.TypeAdapters;
|
||||
import com.massivecraft.mcore4.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore4.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore4.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore4.lib.gson.stream.JsonWriter;
|
||||
import com.massivecraft.mcore4.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.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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.mcore4.lib.gson.reflect.TypeToken
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class Gson {
|
||||
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
||||
|
||||
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
|
||||
|
||||
/**
|
||||
* 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 Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache
|
||||
= Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>());
|
||||
|
||||
private final List<TypeAdapterFactory> factories;
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
private final boolean serializeNulls;
|
||||
private final boolean htmlSafe;
|
||||
private final boolean generateNonExecutableJson;
|
||||
private final boolean prettyPrinting;
|
||||
|
||||
final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
return (T) fromJson(json, typeOfT);
|
||||
}
|
||||
};
|
||||
|
||||
final JsonSerializationContext serializationContext = new JsonSerializationContext() {
|
||||
public JsonElement serialize(Object src) {
|
||||
return toJsonTree(src);
|
||||
}
|
||||
public JsonElement serialize(Object src, Type typeOfSrc) {
|
||||
return toJsonTree(src, typeOfSrc);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.mcore4.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.mcore4.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>
|
||||
*/
|
||||
public Gson() {
|
||||
this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY,
|
||||
Collections.<Type, InstanceCreator<?>>emptyMap(), false, false, DEFAULT_JSON_NON_EXECUTABLE,
|
||||
true, false, false, LongSerializationPolicy.DEFAULT,
|
||||
Collections.<TypeAdapterFactory>emptyList());
|
||||
}
|
||||
|
||||
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingPolicy,
|
||||
final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
||||
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
|
||||
boolean prettyPrinting, boolean serializeSpecialFloatingPointValues,
|
||||
LongSerializationPolicy longSerializationPolicy,
|
||||
List<TypeAdapterFactory> typeAdapterFactories) {
|
||||
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.generateNonExecutableJson = generateNonExecutableGson;
|
||||
this.htmlSafe = htmlSafe;
|
||||
this.prettyPrinting = prettyPrinting;
|
||||
|
||||
TypeAdapterFactory reflectiveTypeAdapterFactory = new ReflectiveTypeAdapterFactory(
|
||||
constructorConstructor, fieldNamingPolicy, excluder);
|
||||
|
||||
ConstructorConstructor constructorConstructor = new ConstructorConstructor();
|
||||
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
|
||||
|
||||
// built-in type adapters that cannot be overridden
|
||||
factories.add(TypeAdapters.STRING_FACTORY);
|
||||
factories.add(TypeAdapters.INTEGER_FACTORY);
|
||||
factories.add(TypeAdapters.BOOLEAN_FACTORY);
|
||||
factories.add(TypeAdapters.BYTE_FACTORY);
|
||||
factories.add(TypeAdapters.SHORT_FACTORY);
|
||||
factories.add(TypeAdapters.newFactory(long.class, Long.class,
|
||||
longAdapter(longSerializationPolicy)));
|
||||
factories.add(TypeAdapters.newFactory(double.class, Double.class,
|
||||
doubleAdapter(serializeSpecialFloatingPointValues)));
|
||||
factories.add(TypeAdapters.newFactory(float.class, Float.class,
|
||||
floatAdapter(serializeSpecialFloatingPointValues)));
|
||||
factories.add(excluder);
|
||||
factories.add(TypeAdapters.NUMBER_FACTORY);
|
||||
factories.add(TypeAdapters.CHARACTER_FACTORY);
|
||||
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
|
||||
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
|
||||
factories.add(TypeAdapters.newFactory(BigDecimal.class, new BigDecimalTypeAdapter()));
|
||||
factories.add(TypeAdapters.newFactory(BigInteger.class, new BigIntegerTypeAdapter()));
|
||||
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
|
||||
factories.add(ObjectTypeAdapter.FACTORY);
|
||||
|
||||
// user's type adapters
|
||||
factories.addAll(typeAdapterFactories);
|
||||
|
||||
// built-in type adapters that can be overridden
|
||||
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
|
||||
factories.add(TypeAdapters.URL_FACTORY);
|
||||
factories.add(TypeAdapters.URI_FACTORY);
|
||||
factories.add(TypeAdapters.UUID_FACTORY);
|
||||
factories.add(TypeAdapters.LOCALE_FACTORY);
|
||||
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
|
||||
factories.add(TypeAdapters.BIT_SET_FACTORY);
|
||||
factories.add(DateTypeAdapter.FACTORY);
|
||||
factories.add(TypeAdapters.CALENDAR_FACTORY);
|
||||
factories.add(TimeTypeAdapter.FACTORY);
|
||||
factories.add(SqlDateTypeAdapter.FACTORY);
|
||||
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
|
||||
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
|
||||
factories.add(ArrayTypeAdapter.FACTORY);
|
||||
factories.add(TypeAdapters.ENUM_FACTORY);
|
||||
factories.add(TypeAdapters.CLASS_FACTORY);
|
||||
factories.add(reflectiveTypeAdapterFactory);
|
||||
|
||||
this.factories = Collections.unmodifiableList(factories);
|
||||
}
|
||||
|
||||
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
|
||||
if (serializeSpecialFloatingPointValues) {
|
||||
return TypeAdapters.DOUBLE;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Double read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return in.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
double doubleValue = value.doubleValue();
|
||||
checkValidFloatingPoint(doubleValue);
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) {
|
||||
if (serializeSpecialFloatingPointValues) {
|
||||
return TypeAdapters.FLOAT;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Float read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return (float) in.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
float floatValue = value.floatValue();
|
||||
checkValidFloatingPoint(floatValue);
|
||||
out.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 in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return in.nextLong();
|
||||
}
|
||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
out.value(value.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type adapter for {@code} type.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
|
||||
TypeAdapter<?> cached = typeTokenCache.get(type);
|
||||
if (cached != null) {
|
||||
return (TypeAdapter<T>) cached;
|
||||
}
|
||||
|
||||
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
|
||||
// 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 (TypeAdapterFactory factory : factories) {
|
||||
TypeAdapter<T> candidate = factory.create(this, type);
|
||||
if (candidate != null) {
|
||||
call.setDelegate(candidate);
|
||||
typeTokenCache.put(type, candidate);
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("GSON cannot handle " + type);
|
||||
} finally {
|
||||
threadCalls.remove(type);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
GsonInternalAccess.INSTANCE = new GsonInternalAccess() {
|
||||
@Override public <T> TypeAdapter<T> getNextAdapter(
|
||||
Gson gson, TypeAdapterFactory skipPast, TypeToken<T> type) {
|
||||
boolean skipPastFound = false;
|
||||
|
||||
for (TypeAdapterFactory factory : gson.factories) {
|
||||
if (!skipPastFound) {
|
||||
if (factory == skipPast) {
|
||||
skipPastFound = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeAdapter<T> candidate = factory.create(gson, type);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("GSON cannot serialize " + type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.mcore4.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
|
||||
*/
|
||||
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
|
||||
JsonTreeWriter writer = new JsonTreeWriter();
|
||||
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.mcore4.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.mcore4.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 = 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.mcore4.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.mcore4.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>) 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.mcore4.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 JsonTreeReader(json), typeOfT);
|
||||
}
|
||||
|
||||
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 in) throws IOException {
|
||||
if (delegate == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return delegate.read(in);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter out, T value) throws IOException {
|
||||
if (delegate == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
delegate.write(out, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{")
|
||||
.append("serializeNulls:").append(serializeNulls)
|
||||
.append("factories:").append(factories)
|
||||
.append(",instanceCreators:").append(constructorConstructor)
|
||||
.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
581
src/com/massivecraft/mcore4/lib/gson/GsonBuilder.java
Normal file
581
src/com/massivecraft/mcore4/lib/gson/GsonBuilder.java
Normal file
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.DefaultDateTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.ExclusionStrategy;
|
||||
import com.massivecraft.mcore4.lib.gson.FieldNamingPolicy;
|
||||
import com.massivecraft.mcore4.lib.gson.FieldNamingStrategy;
|
||||
import com.massivecraft.mcore4.lib.gson.Gson;
|
||||
import com.massivecraft.mcore4.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore4.lib.gson.InstanceCreator;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore4.lib.gson.LongSerializationPolicy;
|
||||
import com.massivecraft.mcore4.lib.gson.TreeTypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore4.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.Excluder;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.bind.TypeAdapters;
|
||||
import com.massivecraft.mcore4.lib.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* <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
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public final class GsonBuilder {
|
||||
private Excluder excluder = Excluder.DEFAULT;
|
||||
private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;
|
||||
private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
|
||||
private final Map<Type, InstanceCreator<?>> instanceCreators
|
||||
= new HashMap<Type, InstanceCreator<?>>();
|
||||
private final List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
|
||||
/** tree-style hierarchy factories. These come after factories for backwards compatibility. */
|
||||
private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<TypeAdapterFactory>();
|
||||
private boolean serializeNulls;
|
||||
private String datePattern;
|
||||
private int dateStyle = DateFormat.DEFAULT;
|
||||
private int timeStyle = DateFormat.DEFAULT;
|
||||
private boolean complexMapKeySerialization;
|
||||
private boolean serializeSpecialFloatingPointValues;
|
||||
private boolean escapeHtmlChars = true;
|
||||
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() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
excluder = excluder.withVersion(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) {
|
||||
excluder = excluder.withModifiers(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.mcore4.lib.gson.annotations.Expose} annotation.
|
||||
*
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
|
||||
excluder = excluder.excludeFieldsWithoutExposeAnnotation();
|
||||
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() {
|
||||
excluder = excluder.disableInnerClassSerialization();
|
||||
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) {
|
||||
this.fieldNamingPolicy = namingConvention;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
this.fieldNamingPolicy = fieldNamingStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply a set of exclusion strategies during both serialization and
|
||||
* deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
|
||||
* This means that if one of the {@code strategies} suggests that a field (or class) should be
|
||||
* skipped then that field (or object) is skipped during serializaiton/deserialization.
|
||||
*
|
||||
* @param strategies the set of strategy object to apply during object (de)serialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.4
|
||||
*/
|
||||
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
excluder = excluder.withExclusionStrategy(strategy, true, true);
|
||||
}
|
||||
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) {
|
||||
excluder = excluder.withExclusionStrategy(strategy, true, false);
|
||||
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) {
|
||||
excluder = excluder.withExclusionStrategy(strategy, false, true);
|
||||
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 TypeAdapter}, {@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 a type adapter 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 TypeAdapter},
|
||||
* {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?>
|
||||
|| typeAdapter instanceof InstanceCreator<?>
|
||||
|| typeAdapter instanceof TypeAdapter<?>);
|
||||
if (Primitives.isPrimitive(type) || Primitives.isWrapperType(type)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot register type adapters for " + type);
|
||||
}
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
instanceCreators.put(type, (InstanceCreator) typeAdapter);
|
||||
}
|
||||
if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
|
||||
TypeToken<?> typeToken = TypeToken.get(type);
|
||||
factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
|
||||
}
|
||||
if (typeAdapter instanceof TypeAdapter<?>) {
|
||||
factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a factory for type adapters. Registering a factory is useful when the type
|
||||
* adapter needs to be configured based on the type of the field being processed. Gson
|
||||
* is designed to handle a large number of factories, so you should consider registering
|
||||
* them to be at par with registering an individual type adapter.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) {
|
||||
factories.add(factory);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
|
||||
* This method combines the registration of a {@link TypeAdapter}, {@link JsonSerializer} and
|
||||
* a {@link JsonDeserializer}. If a type adapter was previously registered for the specified
|
||||
* type hierarchy, it is overridden. If a type adapter 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 {@link TypeAdapter},
|
||||
* {@link JsonSerializer} or {@link JsonDeserializer} interfaces.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?>
|
||||
|| typeAdapter instanceof TypeAdapter<?>);
|
||||
if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) {
|
||||
hierarchyFactories.add(0,
|
||||
TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter));
|
||||
}
|
||||
if (typeAdapter instanceof TypeAdapter<?>) {
|
||||
factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter));
|
||||
}
|
||||
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<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
|
||||
factories.addAll(this.factories);
|
||||
Collections.reverse(factories);
|
||||
factories.addAll(this.hierarchyFactories);
|
||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);
|
||||
|
||||
return new Gson(excluder, fieldNamingPolicy, instanceCreators,
|
||||
serializeNulls, complexMapKeySerialization,
|
||||
generateNonExecutableJson, escapeHtmlChars, prettyPrinting,
|
||||
serializeSpecialFloatingPointValues, longSerializationPolicy, factories);
|
||||
}
|
||||
|
||||
private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
|
||||
List<TypeAdapterFactory> factories) {
|
||||
DefaultDateTypeAdapter dateTypeAdapter;
|
||||
if (datePattern != null && !"".equals(datePattern.trim())) {
|
||||
dateTypeAdapter = new DefaultDateTypeAdapter(datePattern);
|
||||
} else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
|
||||
dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Date.class), dateTypeAdapter));
|
||||
factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Timestamp.class), dateTypeAdapter));
|
||||
factories.add(TreeTypeAdapter.newFactory(TypeToken.get(java.sql.Date.class), dateTypeAdapter));
|
||||
}
|
||||
}
|
||||
94
src/com/massivecraft/mcore4/lib/gson/InstanceCreator.java
Normal file
94
src/com/massivecraft/mcore4/lib/gson/InstanceCreator.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
287
src/com/massivecraft/mcore4/lib/gson/JsonArray.java
Normal file
287
src/com/massivecraft/mcore4/lib/gson/JsonArray.java
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonPrimitive;
|
||||
|
||||
/**
|
||||
* 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,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.mcore4.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
97
src/com/massivecraft/mcore4/lib/gson/JsonDeserializer.java
Normal file
97
src/com/massivecraft/mcore4/lib/gson/JsonDeserializer.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore4.lib.gson.TypeAdapter;
|
||||
|
||||
/**
|
||||
* <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>
|
||||
*
|
||||
* <p>New applications should prefer {@link TypeAdapter}, whose streaming API
|
||||
* is more efficient than this interface's tree API.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
329
src/com/massivecraft/mcore4/lib/gson/JsonElement.java
Normal file
329
src/com/massivecraft/mcore4/lib/gson/JsonElement.java
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore4.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/mcore4/lib/gson/JsonIOException.java
Normal file
47
src/com/massivecraft/mcore4/lib/gson/JsonIOException.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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
61
src/com/massivecraft/mcore4/lib/gson/JsonNull.java
Normal file
61
src/com/massivecraft/mcore4/lib/gson/JsonNull.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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonNull;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
205
src/com/massivecraft/mcore4/lib/gson/JsonObject.java
Normal file
205
src/com/massivecraft/mcore4/lib/gson/JsonObject.java
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore4.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();
|
||||
}
|
||||
}
|
||||
66
src/com/massivecraft/mcore4/lib/gson/JsonParseException.java
Normal file
66
src/com/massivecraft/mcore4/lib/gson/JsonParseException.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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
104
src/com/massivecraft/mcore4/lib/gson/JsonParser.java
Normal file
104
src/com/massivecraft/mcore4/lib/gson/JsonParser.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore4.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore4.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore4.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
338
src/com/massivecraft/mcore4/lib/gson/JsonPrimitive.java
Normal file
338
src/com/massivecraft/mcore4/lib/gson/JsonPrimitive.java
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore4.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore4.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore4.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,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.mcore4.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore4.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore4.lib.gson.JsonSerializer;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user