New bukkit command integration and latest mcore version.
This commit is contained in:
parent
cb5f71f2c8
commit
6536631e6d
@ -2,6 +2,3 @@ name: mcore2
|
||||
version: 1.0.0
|
||||
main: com.massivecraft.mcore2.MCore
|
||||
authors: [Olof Larsson, Brett Flannigan]
|
||||
commands:
|
||||
mcoresilenteater:
|
||||
description: ignore me.
|
@ -5,9 +5,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerPreLoginEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
|
||||
import com.massivecraft.mcore2.persist.IClassManager;
|
||||
import com.massivecraft.mcore2.persist.Persist;
|
||||
@ -23,6 +21,7 @@ public class InternalListener implements Listener
|
||||
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)
|
||||
{
|
||||
@ -40,26 +39,4 @@ public class InternalListener implements Listener
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event)
|
||||
{
|
||||
if (event.isCancelled()) return;
|
||||
if (MCore.handleCommand(event.getPlayer(), event.getMessage().substring(1), false))
|
||||
{
|
||||
Bukkit.getLogger().info("[PLAYER_COMMAND] "+event.getPlayer().getName()+": "+event.getMessage());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private final static String refCommand = "mcoresilenteater";
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onServerCommand(ServerCommandEvent event)
|
||||
{
|
||||
if (event.getCommand().length() == 0) return;
|
||||
if (MCore.handleCommand(event.getSender(), event.getCommand(), false))
|
||||
{
|
||||
event.setCommand(refCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
package com.massivecraft.mcore2;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.massivecraft.mcore2.cmd.Cmd;
|
||||
@ -50,18 +46,6 @@ public class MCore extends JavaPlugin
|
||||
if (cmdInstances.containsKey(owner)) return;
|
||||
cmdInstances.put(owner, new Cmd());
|
||||
}
|
||||
public static boolean handleCommand(CommandSender sender, String commandString, boolean testOnly)
|
||||
{
|
||||
List<String> args = new ArrayList<String>(Arrays.asList(commandString.split("\\s+")));
|
||||
if (args.size() == 0) return false;
|
||||
String alias = args.get(0);
|
||||
args.remove(0);
|
||||
for (Cmd cmd : cmdInstances.values())
|
||||
{
|
||||
if (cmd.handleCommand(sender, alias, args, testOnly)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// ONE
|
||||
@ -125,21 +109,6 @@ public class MCore extends JavaPlugin
|
||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SPOUT INTEGRATION
|
||||
// -------------------------------------------- //
|
||||
/*protected boolean spoutIsIntegrated = false;
|
||||
protected void integrateSpout()
|
||||
{
|
||||
if (spoutIsIntegrated) return;
|
||||
if ( ! Bukkit.getPluginManager().isPluginEnabled("Spout")) return;
|
||||
|
||||
// Ok we should be safe :) Lets integrate!
|
||||
this.spoutIsIntegrated = true;
|
||||
|
||||
|
||||
}*/
|
||||
|
||||
// -------------------------------------------- //
|
||||
// LOGGING
|
||||
// -------------------------------------------- //
|
||||
|
31
src/com/massivecraft/mcore2/cmd/BukkitGlueCommand.java
Normal file
31
src/com/massivecraft/mcore2/cmd/BukkitGlueCommand.java
Normal file
@ -0,0 +1,31 @@
|
||||
package com.massivecraft.mcore2.cmd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
List<String> argList = new ArrayList<String>(Arrays.asList(args));
|
||||
this.mcommand.execute(sender, argList);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -2,17 +2,17 @@ package com.massivecraft.mcore2.cmd;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.mcore2.cmd.arg.AHBoolean;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHByte;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHDate;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHDouble;
|
||||
import com.massivecraft.mcore2.cmd.arg.AHFloat;
|
||||
@ -30,30 +30,19 @@ public class Cmd
|
||||
public <T> IArgHandler<T> getArgHandler(Class<T> clazz) { return (IArgHandler<T>) this.argHandlers.get(clazz); }
|
||||
public <T> void setArgHandler(Class<T> clazz, IArgHandler<T> handler) { this.argHandlers.put(clazz, handler); }
|
||||
|
||||
protected Set<MCommand> commands = new HashSet<MCommand>();
|
||||
public Set<MCommand> getCommands() { return this.commands; }
|
||||
public void addCommand(MCommand mcommand) { this.commands.add(mcommand); }
|
||||
public MCommand getCommand(String alias)
|
||||
/**
|
||||
* @deprecated As of MCore 3, replaced by by {@link MCommand#register()}
|
||||
*/
|
||||
@Deprecated
|
||||
public void addCommand(MCommand mcommand)
|
||||
{
|
||||
for (MCommand command : this.commands)
|
||||
{
|
||||
if (command.aliases.contains(alias)) return command;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean handleCommand(CommandSender sender, String alias, List<String> args, boolean testOnly)
|
||||
{
|
||||
MCommand mcommand = this.getCommand(alias);
|
||||
if (mcommand == null) return false;
|
||||
if (testOnly) return true;
|
||||
mcommand.execute(sender, args);
|
||||
return true;
|
||||
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());
|
||||
@ -62,4 +51,10 @@ public class Cmd
|
||||
this.setArgHandler(Player.class, new AHPlayer());
|
||||
this.setArgHandler(World.class, new AHWorld());
|
||||
}
|
||||
|
||||
public static SimpleCommandMap getBukkitCommandMap()
|
||||
{
|
||||
CraftServer craftServer = (CraftServer)Bukkit.getServer();
|
||||
return craftServer.getCommandMap();
|
||||
}
|
||||
}
|
||||
|
@ -142,35 +142,20 @@ public abstract class MCommand
|
||||
public Player me;
|
||||
public boolean senderIsConsole;
|
||||
|
||||
/*
|
||||
public boolean getSenderIsConsole() { return ! (this.sender instanceof Player); }
|
||||
public Player me()
|
||||
// -------------------------------------------- //
|
||||
// BUKKIT INTEGRATION
|
||||
// -------------------------------------------- //
|
||||
|
||||
public boolean register()
|
||||
{
|
||||
if (sender instanceof Player)
|
||||
{
|
||||
return (Player) sender;
|
||||
}
|
||||
return null;
|
||||
// TODO: Save this somewhere? And update it on changes to the aliases?
|
||||
BukkitGlueCommand bgc = new BukkitGlueCommand(this);
|
||||
return Cmd.getBukkitCommandMap().register("mcore", bgc);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getSenderAs(Class<T> clazz)
|
||||
{
|
||||
if (clazz.isInstance(sender)) return (T) sender;
|
||||
|
||||
for (Persist realm : MCore.getPersistInstances().values())
|
||||
{
|
||||
for (IClassManager<?> manager : realm.getClassManagers().values())
|
||||
{
|
||||
if ( ! manager.getManagedClass().equals(clazz)) continue;
|
||||
if (manager.idCanFix(sender.getClass()) == false) continue;
|
||||
return (T) manager.get(sender);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}*/
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCTORS AND EXECUTOR
|
||||
// -------------------------------------------- //
|
||||
|
||||
public MCommand()
|
||||
{
|
||||
|
16
src/com/massivecraft/mcore2/cmd/arg/AHByte.java
Normal file
16
src/com/massivecraft/mcore2/cmd/arg/AHByte.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.massivecraft.mcore2.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);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* Strategy for excluding anonymous and local classes.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return isAnonymousOrLocal(f.getDeclaredClass());
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return isAnonymousOrLocal(clazz);
|
||||
}
|
||||
|
||||
private boolean isAnonymousOrLocal(Class<?> clazz) {
|
||||
return !Enum.class.isAssignableFrom(clazz)
|
||||
&& (clazz.isAnonymousClass() || clazz.isLocalClass());
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* Defines generic cache interface.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
interface Cache<K, V> {
|
||||
|
||||
/**
|
||||
* Adds the new value object into the cache for the given key. If the key already
|
||||
* exists, then this method will override the value for the key.
|
||||
*
|
||||
* @param key the key identifier for the {@code value} object
|
||||
* @param value the value object to store in the cache
|
||||
*/
|
||||
void addElement(K key, V value);
|
||||
|
||||
/**
|
||||
* Retrieve the cached value for the given {@code key}.
|
||||
*
|
||||
* @param key the key identifying the value
|
||||
* @return the cached value for the given {@code key}
|
||||
*/
|
||||
V getElement(K key);
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Converts the field name that uses camel-case define word separation into separate words that
|
||||
* are separated by the provided {@code separatorString}.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* CamelCaseSeparatorNamingPolicy policy = new CamelCaseSeparatorNamingPolicy("_");
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("integer_Field".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class CamelCaseSeparatorNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
private final String separatorString;
|
||||
|
||||
/**
|
||||
* Constructs a new CamelCaseSeparatorNamingPolicy object that will add the
|
||||
* {@code separatorString} between each of the words separated by camel case.
|
||||
*
|
||||
* @param separatorString the string value to place between words
|
||||
* @throws IllegalArgumentException thrown if the {@code separatorString} parameter
|
||||
* is null or empty.
|
||||
*/
|
||||
public CamelCaseSeparatorNamingPolicy(String separatorString) {
|
||||
$Gson$Preconditions.checkNotNull(separatorString);
|
||||
$Gson$Preconditions.checkArgument(!"".equals(separatorString));
|
||||
this.separatorString = separatorString;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType,
|
||||
Collection<Annotation> annnotations) {
|
||||
StringBuilder translation = new StringBuilder();
|
||||
for (int i = 0; i < target.length(); i++) {
|
||||
char character = target.charAt(i);
|
||||
if (Character.isUpperCase(character) && translation.length() != 0) {
|
||||
translation.append(separatorString);
|
||||
}
|
||||
translation.append(character);
|
||||
}
|
||||
|
||||
return translation.toString();
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Performs numerous field naming translations wrapped up as one object.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
abstract class CompositionFieldNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
private final RecursiveFieldNamingPolicy[] fieldPolicies;
|
||||
|
||||
public CompositionFieldNamingPolicy(RecursiveFieldNamingPolicy... fieldNamingPolicies) {
|
||||
if (fieldNamingPolicies == null) {
|
||||
throw new NullPointerException("naming policies can not be null.");
|
||||
}
|
||||
this.fieldPolicies = fieldNamingPolicies;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
||||
for (RecursiveFieldNamingPolicy policy : fieldPolicies) {
|
||||
target = policy.translateName(target, fieldType, annotations);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
}
|
129
src/com/massivecraft/mcore2/lib/gson/DefaultDateTypeAdapter.java
Normal file
129
src/com/massivecraft/mcore2/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.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.DefaultDateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore2.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();
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* List of all the default type adapters ({@link JsonSerializer}s, {@link JsonDeserializer}s,
|
||||
* and {@link InstanceCreator}s.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class DefaultTypeAdapters {
|
||||
/**
|
||||
* This type adapter supports three subclasses of date: Date, Timestamp, and
|
||||
* java.sql.Date.
|
||||
*/
|
||||
static final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
|
||||
private final DateFormat enUsFormat;
|
||||
private final DateFormat localFormat;
|
||||
private final DateFormat iso8601Format;
|
||||
|
||||
DefaultDateTypeAdapter() {
|
||||
this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
|
||||
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(String datePattern) {
|
||||
this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(int style) {
|
||||
this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
|
||||
}
|
||||
|
||||
public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
|
||||
this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
|
||||
DateFormat.getDateTimeInstance(dateStyle, timeStyle));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
|
||||
this.enUsFormat = enUsFormat;
|
||||
this.localFormat = localFormat;
|
||||
this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
// These methods need to be synchronized since JDK DateFormat classes are not thread-safe
|
||||
// See issue 162
|
||||
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
synchronized (localFormat) {
|
||||
String dateFormatAsString = enUsFormat.format(src);
|
||||
return new JsonPrimitive(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
|
||||
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
if (!(json instanceof JsonPrimitive)) {
|
||||
throw new JsonParseException("The date should be a string value");
|
||||
}
|
||||
Date date = deserializeToDate(json);
|
||||
if (typeOfT == Date.class) {
|
||||
return date;
|
||||
} else if (typeOfT == Timestamp.class) {
|
||||
return new Timestamp(date.getTime());
|
||||
} else if (typeOfT == java.sql.Date.class) {
|
||||
return new java.sql.Date(date.getTime());
|
||||
} else {
|
||||
throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT);
|
||||
}
|
||||
}
|
||||
|
||||
private Date deserializeToDate(JsonElement json) {
|
||||
synchronized (localFormat) {
|
||||
try {
|
||||
return localFormat.parse(json.getAsString());
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
try {
|
||||
return enUsFormat.parse(json.getAsString());
|
||||
} catch (ParseException ignored) {
|
||||
}
|
||||
try {
|
||||
return iso8601Format.parse(json.getAsString());
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(json.getAsString(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(DefaultDateTypeAdapter.class.getSimpleName());
|
||||
sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A wrapper class used to collect numerous {@link ExclusionStrategy} objects
|
||||
* and perform a short-circuited OR operation.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class DisjunctionExclusionStrategy implements ExclusionStrategy {
|
||||
private final Collection<ExclusionStrategy> strategies;
|
||||
|
||||
DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) {
|
||||
this.strategies = $Gson$Preconditions.checkNotNull(strategies);
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
if (strategy.shouldSkipField(f)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
if (strategy.shouldSkipClass(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.ExclusionStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.FieldAttributes;
|
||||
import com.massivecraft.mcore2.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,
|
||||
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Excludes fields that do not have the {@link Expose} annotation
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy {
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
Expose annotation = f.getAnnotation(Expose.class);
|
||||
if (annotation == null) {
|
||||
return true;
|
||||
}
|
||||
return !annotation.deserialize();
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* Excludes fields that do not have the {@link Expose} annotation
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy {
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
Expose annotation = f.getAnnotation(Expose.class);
|
||||
if (annotation == null) {
|
||||
return true;
|
||||
}
|
||||
return !annotation.serialize();
|
||||
}
|
||||
}
|
@ -17,14 +17,12 @@
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Pair;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* A data object that stores attributes of a field.
|
||||
@ -37,60 +35,30 @@ import java.util.Collections;
|
||||
* @since 1.4
|
||||
*/
|
||||
public final class FieldAttributes {
|
||||
private static final String MAX_CACHE_PROPERTY_NAME =
|
||||
"com.google.gson.annotation_cache_size_hint";
|
||||
|
||||
private static final Cache<Pair<Class<?>, String>, Collection<Annotation>> ANNOTATION_CACHE =
|
||||
new LruCache<Pair<Class<?>,String>, Collection<Annotation>>(getMaxCacheSize());
|
||||
|
||||
private final Class<?> declaringClazz;
|
||||
private final Field field;
|
||||
private final Class<?> declaredType;
|
||||
private final boolean isSynthetic;
|
||||
private final int modifiers;
|
||||
private final String name;
|
||||
|
||||
// Fields used for lazy initialization
|
||||
private Type genericType;
|
||||
private Collection<Annotation> annotations;
|
||||
|
||||
/**
|
||||
* Constructs a Field Attributes object from the {@code f}.
|
||||
*
|
||||
* @param f the field to pull attributes from
|
||||
*/
|
||||
FieldAttributes(Class<?> declaringClazz, Field f) {
|
||||
this.declaringClazz = $Gson$Preconditions.checkNotNull(declaringClazz);
|
||||
this.name = f.getName();
|
||||
this.declaredType = f.getType();
|
||||
this.isSynthetic = f.isSynthetic();
|
||||
this.modifiers = f.getModifiers();
|
||||
public FieldAttributes(Field f) {
|
||||
$Gson$Preconditions.checkNotNull(f);
|
||||
this.field = f;
|
||||
}
|
||||
|
||||
private static int getMaxCacheSize() {
|
||||
final int defaultMaxCacheSize = 2000;
|
||||
try {
|
||||
String propertyValue = System.getProperty(
|
||||
MAX_CACHE_PROPERTY_NAME, String.valueOf(defaultMaxCacheSize));
|
||||
return Integer.parseInt(propertyValue);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultMaxCacheSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the declaring class that contains this field
|
||||
*/
|
||||
public Class<?> getDeclaringClass() {
|
||||
return declaringClazz;
|
||||
return field.getDeclaringClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the field
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
return field.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,10 +78,7 @@ public final class FieldAttributes {
|
||||
* @return the specific type declared for this field
|
||||
*/
|
||||
public Type getDeclaredType() {
|
||||
if (genericType == null) {
|
||||
genericType = field.getGenericType();
|
||||
}
|
||||
return genericType;
|
||||
return field.getGenericType();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,7 +98,7 @@ public final class FieldAttributes {
|
||||
* @return the specific class object that was declared for the field
|
||||
*/
|
||||
public Class<?> getDeclaredClass() {
|
||||
return declaredType;
|
||||
return field.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,7 +109,7 @@ public final class FieldAttributes {
|
||||
* @return the annotation instance if it is bound to the field; otherwise {@code null}
|
||||
*/
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotation) {
|
||||
return getAnnotationFromArray(getAnnotations(), annotation);
|
||||
return field.getAnnotation(annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,17 +119,7 @@ public final class FieldAttributes {
|
||||
* @since 1.4
|
||||
*/
|
||||
public Collection<Annotation> getAnnotations() {
|
||||
if (annotations == null) {
|
||||
Pair<Class<?>, String> key = new Pair<Class<?>, String>(declaringClazz, name);
|
||||
Collection<Annotation> cachedValue = ANNOTATION_CACHE.getElement(key);
|
||||
if (cachedValue == null) {
|
||||
cachedValue = Collections.unmodifiableCollection(
|
||||
Arrays.asList(field.getAnnotations()));
|
||||
ANNOTATION_CACHE.addElement(key, cachedValue);
|
||||
}
|
||||
annotations = cachedValue;
|
||||
}
|
||||
return annotations;
|
||||
return Arrays.asList(field.getAnnotations());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,7 +133,7 @@ public final class FieldAttributes {
|
||||
* @see java.lang.reflect.Modifier
|
||||
*/
|
||||
public boolean hasModifier(int modifier) {
|
||||
return (modifiers & modifier) != 0;
|
||||
return (field.getModifiers() & modifier) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,25 +153,6 @@ public final class FieldAttributes {
|
||||
* @return true if the field is synthetic; otherwise false
|
||||
*/
|
||||
boolean isSynthetic() {
|
||||
return isSynthetic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated remove this when {@link FieldNamingStrategy} is deleted.
|
||||
*/
|
||||
@Deprecated
|
||||
Field getFieldObject() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Annotation> T getAnnotationFromArray(
|
||||
Collection<Annotation> annotations, Class<T> annotation) {
|
||||
for (Annotation a : annotations) {
|
||||
if (a.annotationType() == annotation) {
|
||||
return (T) a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return field.isSynthetic();
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.massivecraft.mcore2.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.mcore2.lib.gson.GsonBuilder}
|
||||
@ -25,7 +29,18 @@ package com.massivecraft.mcore2.lib.gson;
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public enum FieldNamingPolicy {
|
||||
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.
|
||||
@ -36,8 +51,11 @@ public enum FieldNamingPolicy {
|
||||
* <li>_someFieldName ---> _SomeFieldName</li>
|
||||
* </ul>
|
||||
*/
|
||||
UPPER_CAMEL_CASE(new ModifyFirstLetterNamingPolicy(
|
||||
ModifyFirstLetterNamingPolicy.LetterModifier.UPPER)),
|
||||
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
|
||||
@ -52,7 +70,11 @@ public enum FieldNamingPolicy {
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
UPPER_CAMEL_CASE_WITH_SPACES(new UpperCamelCaseSeparatorNamingPolicy(" ")),
|
||||
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
|
||||
@ -66,7 +88,11 @@ public enum FieldNamingPolicy {
|
||||
* <li>aURL ---> a_u_r_l</li>
|
||||
* </ul>
|
||||
*/
|
||||
LOWER_CASE_WITH_UNDERSCORES(new LowerCamelCaseSeparatorNamingPolicy("_")),
|
||||
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
|
||||
@ -85,15 +111,60 @@ public enum FieldNamingPolicy {
|
||||
* {@code myobject.my-field} will result in an unintended javascript expression.
|
||||
* @since 1.4
|
||||
*/
|
||||
LOWER_CASE_WITH_DASHES(new LowerCamelCaseSeparatorNamingPolicy("-"));
|
||||
LOWER_CASE_WITH_DASHES() {
|
||||
public String translateName(Field f) {
|
||||
return separateCamelCase(f.getName(), "-").toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
private final FieldNamingStrategy2 namingPolicy;
|
||||
|
||||
private FieldNamingPolicy(FieldNamingStrategy2 namingPolicy) {
|
||||
this.namingPolicy = namingPolicy;
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
FieldNamingStrategy2 getFieldNamingPolicy() {
|
||||
return namingPolicy;
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* The new mechanism for providing custom field naming in Gson. This allows the client code
|
||||
* to translate field names into a particular convention that is not supported as a normal
|
||||
* Java field declaration rules. For example, Java does not support "-" characters in a
|
||||
* field name.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
interface FieldNamingStrategy2 {
|
||||
|
||||
/**
|
||||
* Translates the field name into its JSON field name representation.
|
||||
*
|
||||
* @param f the field that is being translated
|
||||
* @return the translated field name.
|
||||
*/
|
||||
public String translateName(FieldAttributes f);
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
/**
|
||||
* Adapts the old FieldNamingStrategy to the new {@link FieldNamingStrategy2}
|
||||
* type.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 {
|
||||
private final FieldNamingStrategy adaptee;
|
||||
|
||||
FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) {
|
||||
this.adaptee = $Gson$Preconditions.checkNotNull(adaptee);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public String translateName(FieldAttributes f) {
|
||||
return adaptee.translateName(f.getFieldObject());
|
||||
}
|
||||
}
|
@ -16,8 +16,26 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.FieldNamingPolicy;
|
||||
import com.massivecraft.mcore2.lib.gson.FieldNamingStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore2.lib.gson.InstanceCreator;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.LongSerializationPolicy;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Excluder;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.GsonInternalAccess;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ArrayTypeAdapter;
|
||||
@ -25,16 +43,13 @@ import com.massivecraft.mcore2.lib.gson.internal.bind.BigDecimalTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.BigIntegerTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.CollectionTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.DateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ExcludedTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonElementReader;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonElementWriter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonTreeReader;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonTreeWriter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.MapTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.MiniGson;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ObjectTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ReflectiveTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.SqlDateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TimeTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapters;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
@ -48,13 +63,12 @@ import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -101,42 +115,50 @@ import java.util.Map;
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class Gson {
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final ParameterizedTypeHandlerMap EMPTY_MAP =
|
||||
new ParameterizedTypeHandlerMap().makeUnmodifiable();
|
||||
|
||||
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
||||
|
||||
// Default instances of plug-ins
|
||||
static final AnonymousAndLocalClassExclusionStrategy DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY =
|
||||
new AnonymousAndLocalClassExclusionStrategy();
|
||||
static final SyntheticFieldExclusionStrategy DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY =
|
||||
new SyntheticFieldExclusionStrategy(true);
|
||||
static final ModifierBasedExclusionStrategy DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY =
|
||||
new ModifierBasedExclusionStrategy(Modifier.TRANSIENT, Modifier.STATIC);
|
||||
static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY =
|
||||
new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy());
|
||||
|
||||
private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy();
|
||||
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
||||
|
||||
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
|
||||
|
||||
private final ExclusionStrategy deserializationExclusionStrategy;
|
||||
private final ExclusionStrategy serializationExclusionStrategy;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/** Map containing Type or Class objects as keys */
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
|
||||
/** Map containing Type or Class objects as keys */
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
|
||||
private final boolean serializeNulls;
|
||||
private final boolean htmlSafe;
|
||||
private final boolean generateNonExecutableJson;
|
||||
private final boolean prettyPrinting;
|
||||
|
||||
private final MiniGson miniGson;
|
||||
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
|
||||
@ -172,110 +194,76 @@ public final class Gson {
|
||||
* {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Gson() {
|
||||
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
|
||||
EMPTY_MAP, false, EMPTY_MAP, EMPTY_MAP, false, DEFAULT_JSON_NON_EXECUTABLE, true,
|
||||
false, false, LongSerializationPolicy.DEFAULT,
|
||||
Collections.<TypeAdapter.Factory>emptyList());
|
||||
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 ExclusionStrategy deserializationExclusionStrategy,
|
||||
final ExclusionStrategy serializationExclusionStrategy,
|
||||
final FieldNamingStrategy2 fieldNamingPolicy,
|
||||
final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
||||
final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
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<TypeAdapter.Factory> typeAdapterFactories) {
|
||||
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
|
||||
this.serializationExclusionStrategy = serializationExclusionStrategy;
|
||||
List<TypeAdapterFactory> typeAdapterFactories) {
|
||||
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
this.generateNonExecutableJson = generateNonExecutableGson;
|
||||
this.htmlSafe = htmlSafe;
|
||||
this.prettyPrinting = prettyPrinting;
|
||||
|
||||
/*
|
||||
TODO: for serialization, honor:
|
||||
serializationExclusionStrategy
|
||||
fieldNamingPolicy
|
||||
serializeNulls
|
||||
serializers
|
||||
*/
|
||||
TypeAdapter.Factory reflectiveTypeAdapterFactory
|
||||
= new ReflectiveTypeAdapterFactory(constructorConstructor) {
|
||||
@Override
|
||||
public String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return fieldNamingPolicy.translateName(new FieldAttributes(declaringClazz, f));
|
||||
}
|
||||
@Override
|
||||
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
ExclusionStrategy strategy = Gson.this.serializationExclusionStrategy;
|
||||
return !strategy.shouldSkipClass(f.getType())
|
||||
&& !strategy.shouldSkipField(new FieldAttributes(declaringClazz, f));
|
||||
}
|
||||
TypeAdapterFactory reflectiveTypeAdapterFactory = new ReflectiveTypeAdapterFactory(
|
||||
constructorConstructor, fieldNamingPolicy, excluder);
|
||||
|
||||
@Override
|
||||
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
ExclusionStrategy strategy = Gson.this.deserializationExclusionStrategy;
|
||||
return !strategy.shouldSkipClass(f.getType())
|
||||
&& !strategy.shouldSkipField(new FieldAttributes(declaringClazz, f));
|
||||
}
|
||||
};
|
||||
ConstructorConstructor constructorConstructor = new ConstructorConstructor();
|
||||
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
|
||||
|
||||
MiniGson.Builder builder = new MiniGson.Builder()
|
||||
.withoutDefaultFactories()
|
||||
.factory(TypeAdapters.STRING_FACTORY)
|
||||
.factory(TypeAdapters.INTEGER_FACTORY)
|
||||
.factory(TypeAdapters.BOOLEAN_FACTORY)
|
||||
.factory(TypeAdapters.BYTE_FACTORY)
|
||||
.factory(TypeAdapters.SHORT_FACTORY)
|
||||
.factory(TypeAdapters.newFactory(long.class, Long.class,
|
||||
longAdapter(longSerializationPolicy)))
|
||||
.factory(TypeAdapters.newFactory(double.class, Double.class,
|
||||
doubleAdapter(serializeSpecialFloatingPointValues)))
|
||||
.factory(TypeAdapters.newFactory(float.class, Float.class,
|
||||
floatAdapter(serializeSpecialFloatingPointValues)))
|
||||
.factory(new ExcludedTypeAdapterFactory(
|
||||
serializationExclusionStrategy, deserializationExclusionStrategy))
|
||||
.factory(TypeAdapters.NUMBER_FACTORY)
|
||||
.factory(TypeAdapters.CHARACTER_FACTORY)
|
||||
.factory(TypeAdapters.STRING_BUILDER_FACTORY)
|
||||
.factory(TypeAdapters.STRING_BUFFER_FACTORY)
|
||||
.typeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
|
||||
.typeAdapter(BigInteger.class, new BigIntegerTypeAdapter())
|
||||
.factory(TypeAdapters.JSON_ELEMENT_FACTORY)
|
||||
.factory(ObjectTypeAdapter.FACTORY);
|
||||
// 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);
|
||||
|
||||
for (TypeAdapter.Factory factory : typeAdapterFactories) {
|
||||
builder.factory(factory);
|
||||
}
|
||||
// user's type adapters
|
||||
factories.addAll(typeAdapterFactories);
|
||||
|
||||
builder
|
||||
.factory(new GsonToMiniGsonTypeAdapterFactory(this, serializers, deserializers))
|
||||
.factory(new CollectionTypeAdapterFactory(constructorConstructor))
|
||||
.factory(TypeAdapters.URL_FACTORY)
|
||||
.factory(TypeAdapters.URI_FACTORY)
|
||||
.factory(TypeAdapters.UUID_FACTORY)
|
||||
.factory(TypeAdapters.LOCALE_FACTORY)
|
||||
.factory(TypeAdapters.INET_ADDRESS_FACTORY)
|
||||
.factory(TypeAdapters.BIT_SET_FACTORY)
|
||||
.factory(DateTypeAdapter.FACTORY)
|
||||
.factory(TypeAdapters.CALENDAR_FACTORY)
|
||||
.factory(TimeTypeAdapter.FACTORY)
|
||||
.factory(SqlDateTypeAdapter.FACTORY)
|
||||
.factory(TypeAdapters.TIMESTAMP_FACTORY)
|
||||
.factory(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization))
|
||||
.factory(ArrayTypeAdapter.FACTORY)
|
||||
.factory(TypeAdapters.ENUM_FACTORY)
|
||||
.factory(reflectiveTypeAdapterFactory);
|
||||
// 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.miniGson = builder.build();
|
||||
this.factories = Collections.unmodifiableList(factories);
|
||||
}
|
||||
|
||||
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
|
||||
@ -283,21 +271,21 @@ public final class Gson {
|
||||
return TypeAdapters.DOUBLE;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Double read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
@Override public Double read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return reader.nextDouble();
|
||||
return in.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
double doubleValue = value.doubleValue();
|
||||
checkValidFloatingPoint(doubleValue);
|
||||
writer.value(value);
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -307,21 +295,21 @@ public final class Gson {
|
||||
return TypeAdapters.FLOAT;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Float read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
@Override public Float read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return (float) reader.nextDouble();
|
||||
return (float) in.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
float floatValue = value.floatValue();
|
||||
checkValidFloatingPoint(floatValue);
|
||||
writer.value(value);
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -339,29 +327,93 @@ public final class Gson {
|
||||
return TypeAdapters.LONG;
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
@Override public Number read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return reader.nextLong();
|
||||
return in.nextLong();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
writer.value(value.toString());
|
||||
out.value(value.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ExclusionStrategy createExclusionStrategy() {
|
||||
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
|
||||
strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
|
||||
return new DisjunctionExclusionStrategy(strategies);
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -400,9 +452,8 @@ public final class Gson {
|
||||
* @return Json representation of {@code src}
|
||||
* @since 1.4
|
||||
*/
|
||||
// the caller is required to make src and typeOfSrc consistent
|
||||
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
|
||||
JsonElementWriter writer = new JsonElementWriter();
|
||||
JsonTreeWriter writer = new JsonTreeWriter();
|
||||
toJson(src, typeOfSrc, writer);
|
||||
return writer.get();
|
||||
}
|
||||
@ -502,7 +553,7 @@ public final class Gson {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
|
||||
TypeAdapter<?> adapter = miniGson.getAdapter(TypeToken.get(typeOfSrc));
|
||||
TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
|
||||
boolean oldLenient = writer.isLenient();
|
||||
writer.setLenient(true);
|
||||
boolean oldHtmlSafe = writer.isHtmlSafe();
|
||||
@ -683,7 +734,7 @@ public final class Gson {
|
||||
* @since 1.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
||||
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);
|
||||
@ -718,7 +769,7 @@ public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyn
|
||||
try {
|
||||
reader.peek();
|
||||
isEmpty = false;
|
||||
TypeAdapter<T> typeAdapter = (TypeAdapter<T>) miniGson.getAdapter(TypeToken.get(typeOfT));
|
||||
TypeAdapter<T> typeAdapter = (TypeAdapter<T>) getAdapter(TypeToken.get(typeOfT));
|
||||
return typeAdapter.read(reader);
|
||||
} catch (EOFException e) {
|
||||
/*
|
||||
@ -779,26 +830,45 @@ public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyn
|
||||
* @since 1.3
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
|
||||
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
return (T) fromJson(new JsonElementReader(json), typeOfT);
|
||||
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(",serializers:").append(serializers)
|
||||
.append(",deserializers:").append(deserializers)
|
||||
|
||||
// using the name instanceCreator instead of ObjectConstructor since the users of Gson are
|
||||
// more familiar with the concept of Instance Creators. Moreover, the objectConstructor is
|
||||
// just a utility class around instance creators, and its toString() only displays them.
|
||||
.append("factories:").append(factories)
|
||||
.append(",instanceCreators:").append(constructorConstructor)
|
||||
.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,22 +16,35 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapter;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.DefaultDateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.ExclusionStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.FieldNamingPolicy;
|
||||
import com.massivecraft.mcore2.lib.gson.FieldNamingStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore2.lib.gson.InstanceCreator;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore2.lib.gson.LongSerializationPolicy;
|
||||
import com.massivecraft.mcore2.lib.gson.TreeTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Excluder;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapters;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
|
||||
@ -65,40 +78,24 @@ import java.util.Set;
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public final class GsonBuilder {
|
||||
private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
|
||||
new InnerClassExclusionStrategy();
|
||||
private static final ExposeAnnotationDeserializationExclusionStrategy
|
||||
exposeAnnotationDeserializationExclusionStrategy =
|
||||
new ExposeAnnotationDeserializationExclusionStrategy();
|
||||
private static final ExposeAnnotationSerializationExclusionStrategy
|
||||
exposeAnnotationSerializationExclusionStrategy =
|
||||
new ExposeAnnotationSerializationExclusionStrategy();
|
||||
|
||||
private final Set<ExclusionStrategy> serializeExclusionStrategies =
|
||||
new HashSet<ExclusionStrategy>();
|
||||
private final Set<ExclusionStrategy> deserializeExclusionStrategies =
|
||||
new HashSet<ExclusionStrategy>();
|
||||
|
||||
private double ignoreVersionsAfter;
|
||||
private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy;
|
||||
private boolean serializeInnerClasses;
|
||||
private boolean excludeFieldsWithoutExposeAnnotation;
|
||||
private LongSerializationPolicy longSerializationPolicy;
|
||||
private FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final List<TypeAdapter.Factory> typeAdapterFactories
|
||||
= new ArrayList<TypeAdapter.Factory>();
|
||||
private 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;
|
||||
private int timeStyle;
|
||||
private boolean complexMapKeySerialization = false;
|
||||
private int dateStyle = DateFormat.DEFAULT;
|
||||
private int timeStyle = DateFormat.DEFAULT;
|
||||
private boolean complexMapKeySerialization;
|
||||
private boolean serializeSpecialFloatingPointValues;
|
||||
private boolean escapeHtmlChars;
|
||||
private boolean escapeHtmlChars = true;
|
||||
private boolean prettyPrinting;
|
||||
private boolean generateNonExecutableJson;
|
||||
|
||||
@ -109,29 +106,6 @@ public final class GsonBuilder {
|
||||
* {@link #create()}.
|
||||
*/
|
||||
public GsonBuilder() {
|
||||
// add default exclusion strategies
|
||||
deserializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
deserializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
serializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
serializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
|
||||
// setup default values
|
||||
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
|
||||
serializeInnerClasses = true;
|
||||
prettyPrinting = false;
|
||||
escapeHtmlChars = true;
|
||||
modifierBasedExclusionStrategy = Gson.DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY;
|
||||
excludeFieldsWithoutExposeAnnotation = false;
|
||||
longSerializationPolicy = LongSerializationPolicy.DEFAULT;
|
||||
fieldNamingPolicy = Gson.DEFAULT_NAMING_POLICY;
|
||||
instanceCreators = new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||
serializers = new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
||||
deserializers = new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
||||
serializeNulls = false;
|
||||
dateStyle = DateFormat.DEFAULT;
|
||||
timeStyle = DateFormat.DEFAULT;
|
||||
serializeSpecialFloatingPointValues = false;
|
||||
generateNonExecutableJson = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +116,7 @@ public final class GsonBuilder {
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder setVersion(double ignoreVersionsAfter) {
|
||||
this.ignoreVersionsAfter = ignoreVersionsAfter;
|
||||
excluder = excluder.withVersion(ignoreVersionsAfter);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -158,7 +132,7 @@ public final class GsonBuilder {
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder excludeFieldsWithModifiers(int... modifiers) {
|
||||
modifierBasedExclusionStrategy = new ModifierBasedExclusionStrategy(modifiers);
|
||||
excluder = excluder.withModifiers(modifiers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -183,7 +157,7 @@ public final class GsonBuilder {
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
|
||||
excludeFieldsWithoutExposeAnnotation = true;
|
||||
excluder = excluder.excludeFieldsWithoutExposeAnnotation();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -287,7 +261,7 @@ public final class GsonBuilder {
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder disableInnerClassSerialization() {
|
||||
serializeInnerClasses = false;
|
||||
excluder = excluder.disableInnerClassSerialization();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -313,7 +287,8 @@ public final class GsonBuilder {
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {
|
||||
return setFieldNamingStrategy(namingConvention.getFieldNamingPolicy());
|
||||
this.fieldNamingPolicy = namingConvention;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,19 +300,7 @@ public final class GsonBuilder {
|
||||
* @since 1.3
|
||||
*/
|
||||
public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
|
||||
return setFieldNamingStrategy(new FieldNamingStrategy2Adapter(fieldNamingStrategy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply a specific naming policy strategy to an object's field during
|
||||
* serialization and deserialization.
|
||||
*
|
||||
* @param fieldNamingStrategy the actual naming strategy to apply to the fields
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
GsonBuilder setFieldNamingStrategy(FieldNamingStrategy2 fieldNamingStrategy) {
|
||||
this.fieldNamingPolicy =
|
||||
new SerializedNameAnnotationInterceptingNamingPolicy(fieldNamingStrategy);
|
||||
this.fieldNamingPolicy = fieldNamingStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -352,9 +315,9 @@ public final class GsonBuilder {
|
||||
* @since 1.4
|
||||
*/
|
||||
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
|
||||
List<ExclusionStrategy> strategyList = Arrays.asList(strategies);
|
||||
serializeExclusionStrategies.addAll(strategyList);
|
||||
deserializeExclusionStrategies.addAll(strategyList);
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
excluder = excluder.withExclusionStrategy(strategy, true, true);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -371,7 +334,7 @@ public final class GsonBuilder {
|
||||
* @since 1.7
|
||||
*/
|
||||
public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
|
||||
serializeExclusionStrategies.add(strategy);
|
||||
excluder = excluder.withExclusionStrategy(strategy, true, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -388,7 +351,7 @@ public final class GsonBuilder {
|
||||
* @since 1.7
|
||||
*/
|
||||
public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
|
||||
deserializeExclusionStrategies.add(strategy);
|
||||
excluder = excluder.withExclusionStrategy(strategy, false, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -481,147 +444,78 @@ public final class GsonBuilder {
|
||||
|
||||
/**
|
||||
* Configures Gson for custom serialization or deserialization. This method combines the
|
||||
* registration of an {@link InstanceCreator}, {@link JsonSerializer}, and a
|
||||
* 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 an instance creator,
|
||||
* serializer or deserializer was previously registered for the specified {@code type}, it is
|
||||
* overwritten.
|
||||
* 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 InstanceCreator},
|
||||
* {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
|
||||
* @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) {
|
||||
return registerTypeAdapter(type, typeAdapter, false);
|
||||
}
|
||||
|
||||
private GsonBuilder registerTypeAdapter(Type type, Object typeAdapter, boolean isSystem) {
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?>
|
||||
|| typeAdapter instanceof InstanceCreator<?>
|
||||
|| typeAdapter instanceof TypeAdapter.Factory);
|
||||
|| typeAdapter instanceof TypeAdapter<?>);
|
||||
if (Primitives.isPrimitive(type) || Primitives.isWrapperType(type)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot register type adapters for " + type);
|
||||
}
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter, isSystem);
|
||||
instanceCreators.put(type, (InstanceCreator) typeAdapter);
|
||||
}
|
||||
if (typeAdapter instanceof JsonSerializer<?>) {
|
||||
registerSerializer(type, (JsonSerializer<?>) typeAdapter, isSystem);
|
||||
if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
|
||||
TypeToken<?> typeToken = TypeToken.get(type);
|
||||
factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
|
||||
}
|
||||
if (typeAdapter instanceof JsonDeserializer<?>) {
|
||||
registerDeserializer(type, (JsonDeserializer<?>) typeAdapter, isSystem);
|
||||
}
|
||||
if (typeAdapter instanceof TypeAdapter.Factory) {
|
||||
typeAdapterFactories.add((TypeAdapter.Factory) typeAdapter);
|
||||
if (typeAdapter instanceof TypeAdapter<?>) {
|
||||
factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to use a custom {@link InstanceCreator} for the specified type. If an instance
|
||||
* creator was previously registered for the specified class, it is overwritten. Since this method
|
||||
* takes a type instead of a Class object, it can be used to register a specific handler for a
|
||||
* generic type corresponding to a raw type.
|
||||
* 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.
|
||||
*
|
||||
* @param <T> the type for which instance creator is being registered
|
||||
* @param typeOfT The Type definition for T
|
||||
* @param instanceCreator the instance creator for T
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 2.1
|
||||
*/
|
||||
private <T> GsonBuilder registerInstanceCreator(Type typeOfT,
|
||||
InstanceCreator<? extends T> instanceCreator, boolean isSystem) {
|
||||
instanceCreators.register(typeOfT, instanceCreator, isSystem);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to use a custom JSON serializer for the specified type. You should use this
|
||||
* method if you want to register different serializers for different generic types corresponding
|
||||
* to a raw type.
|
||||
*
|
||||
* @param <T> the type for which the serializer is being registered
|
||||
* @param typeOfT The type definition for T
|
||||
* @param serializer the custom serializer
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
private <T> GsonBuilder registerSerializer(Type typeOfT, JsonSerializer<T> serializer,
|
||||
boolean isSystem) {
|
||||
serializers.register(typeOfT, serializer, isSystem);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to use a custom JSON deserializer for the specified type. You should use this
|
||||
* method if you want to register different deserializers for different generic types
|
||||
* corresponding to a raw type.
|
||||
*
|
||||
* @param <T> the type for which the deserializer is being registered
|
||||
* @param typeOfT The type definition for T
|
||||
* @param deserializer the custom deserializer
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
*/
|
||||
private <T> GsonBuilder registerDeserializer(Type typeOfT, JsonDeserializer<T> deserializer,
|
||||
boolean isSystem) {
|
||||
deserializers.register(typeOfT, new JsonDeserializerExceptionWrapper<T>(deserializer), isSystem);
|
||||
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 an {@link InstanceCreator}, {@link JsonSerializer},
|
||||
* and a {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter}
|
||||
* implements all the required interfaces for custom serialization with Gson.
|
||||
* If an instance creator, serializer or deserializer was previously registered for the specified
|
||||
* type hierarchy, it is overwritten. If an instance creator, serializer or deserializer is
|
||||
* registered for a specific type in the type hierarchy, it will be invoked instead of the one
|
||||
* registered for the type hierarchy.
|
||||
* 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 the {@link InstanceCreator},
|
||||
* {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
|
||||
* @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) {
|
||||
return registerTypeHierarchyAdapter(baseType, typeAdapter, false);
|
||||
}
|
||||
|
||||
private GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter,
|
||||
boolean isSystem) {
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator<?>) typeAdapter, isSystem);
|
||||
|| typeAdapter instanceof JsonDeserializer<?>
|
||||
|| typeAdapter instanceof TypeAdapter<?>);
|
||||
if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) {
|
||||
hierarchyFactories.add(0,
|
||||
TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter));
|
||||
}
|
||||
if (typeAdapter instanceof JsonSerializer<?>) {
|
||||
registerSerializerForTypeHierarchy(baseType, (JsonSerializer<?>) typeAdapter, isSystem);
|
||||
if (typeAdapter instanceof TypeAdapter<?>) {
|
||||
factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter));
|
||||
}
|
||||
if (typeAdapter instanceof JsonDeserializer<?>) {
|
||||
registerDeserializerForTypeHierarchy(baseType, (JsonDeserializer<?>) typeAdapter, isSystem);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerInstanceCreatorForTypeHierarchy(Class<?> classOfT,
|
||||
InstanceCreator<? extends T> instanceCreator, boolean isSystem) {
|
||||
instanceCreators.registerForTypeHierarchy(classOfT, instanceCreator, isSystem);
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerSerializerForTypeHierarchy(Class<?> classOfT,
|
||||
JsonSerializer<T> serializer, boolean isSystem) {
|
||||
serializers.registerForTypeHierarchy(classOfT, serializer, isSystem);
|
||||
return this;
|
||||
}
|
||||
|
||||
private <T> GsonBuilder registerDeserializerForTypeHierarchy(Class<?> classOfT,
|
||||
JsonDeserializer<T> deserializer, boolean isSystem) {
|
||||
deserializers.registerForTypeHierarchy(classOfT,
|
||||
new JsonDeserializerExceptionWrapper<T>(deserializer), isSystem);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -657,61 +551,31 @@ public final class GsonBuilder {
|
||||
* @return an instance of Gson configured with the options currently set in this builder
|
||||
*/
|
||||
public Gson create() {
|
||||
List<ExclusionStrategy> deserializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(deserializeExclusionStrategies);
|
||||
List<ExclusionStrategy> serializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(serializeExclusionStrategies);
|
||||
deserializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
serializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
|
||||
factories.addAll(this.factories);
|
||||
Collections.reverse(factories);
|
||||
factories.addAll(this.hierarchyFactories);
|
||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);
|
||||
|
||||
if (!serializeInnerClasses) {
|
||||
deserializationStrategies.add(innerClassExclusionStrategy);
|
||||
serializationStrategies.add(innerClassExclusionStrategy);
|
||||
}
|
||||
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
|
||||
VersionExclusionStrategy versionExclusionStrategy =
|
||||
new VersionExclusionStrategy(ignoreVersionsAfter);
|
||||
deserializationStrategies.add(versionExclusionStrategy);
|
||||
serializationStrategies.add(versionExclusionStrategy);
|
||||
}
|
||||
if (excludeFieldsWithoutExposeAnnotation) {
|
||||
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
|
||||
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
|
||||
}
|
||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, serializers, deserializers);
|
||||
|
||||
return new Gson(new DisjunctionExclusionStrategy(deserializationStrategies),
|
||||
new DisjunctionExclusionStrategy(serializationStrategies),
|
||||
fieldNamingPolicy, instanceCreators.copyOf().makeUnmodifiable(), serializeNulls,
|
||||
serializers.copyOf().makeUnmodifiable(), deserializers.copyOf().makeUnmodifiable(),
|
||||
complexMapKeySerialization, generateNonExecutableJson, escapeHtmlChars, prettyPrinting,
|
||||
serializeSpecialFloatingPointValues, longSerializationPolicy, typeAdapterFactories);
|
||||
return new Gson(excluder, fieldNamingPolicy, instanceCreators,
|
||||
serializeNulls, complexMapKeySerialization,
|
||||
generateNonExecutableJson, escapeHtmlChars, prettyPrinting,
|
||||
serializeSpecialFloatingPointValues, longSerializationPolicy, factories);
|
||||
}
|
||||
|
||||
private static void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers) {
|
||||
DefaultDateTypeAdapter dateTypeAdapter = null;
|
||||
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;
|
||||
}
|
||||
|
||||
if (dateTypeAdapter != null) {
|
||||
registerIfAbsent(Date.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(Date.class, deserializers, dateTypeAdapter);
|
||||
registerIfAbsent(Timestamp.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(Timestamp.class, deserializers, dateTypeAdapter);
|
||||
registerIfAbsent(java.sql.Date.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(java.sql.Date.class, deserializers, dateTypeAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void registerIfAbsent(Class<?> type,
|
||||
ParameterizedTypeHandlerMap<T> adapters, T adapter) {
|
||||
if (!adapters.hasSpecificHandlerFor(type)) {
|
||||
adapters.register(type, adapter, false);
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.MiniGson;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
final class GsonToMiniGsonTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final JsonDeserializationContext deserializationContext;
|
||||
private final JsonSerializationContext serializationContext;
|
||||
|
||||
public GsonToMiniGsonTypeAdapterFactory(final Gson gson,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers) {
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
|
||||
this.deserializationContext = new JsonDeserializationContext() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
return (T) gson.fromJson(json, typeOfT);
|
||||
}
|
||||
};
|
||||
|
||||
this.serializationContext = new JsonSerializationContext() {
|
||||
public JsonElement serialize(Object src) {
|
||||
return gson.toJsonTree(src);
|
||||
}
|
||||
public JsonElement serialize(Object src, Type typeOfSrc) {
|
||||
return gson.toJsonTree(src, typeOfSrc);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final MiniGson context, final TypeToken<T> typeToken) {
|
||||
final Type type = typeToken.getType();
|
||||
|
||||
@SuppressWarnings("unchecked") // guaranteed to match typeOfT
|
||||
final JsonSerializer<T> serializer
|
||||
= (JsonSerializer<T>) serializers.getHandlerFor(type, false);
|
||||
@SuppressWarnings("unchecked") // guaranteed to match typeOfT
|
||||
final JsonDeserializer<T> deserializer
|
||||
= (JsonDeserializer<T>) deserializers.getHandlerFor(type, false);
|
||||
|
||||
if (serializer == null && deserializer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
/**
|
||||
* The delegate is lazily created because it may not be needed, and
|
||||
* creating it may fail.
|
||||
*/
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (deserializer == null) {
|
||||
return delegate().read(reader);
|
||||
}
|
||||
JsonElement value = Streams.parse(reader);
|
||||
if (value.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
return deserializer.deserialize(value, type, deserializationContext);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (serializer == null) {
|
||||
delegate().write(writer, value);
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
JsonElement element = serializer.serialize(value, type, serializationContext);
|
||||
Streams.write(element, writer);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = context.getNextAdapter(GsonToMiniGsonTypeAdapterFactory.this, typeToken));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Strategy for excluding inner classes.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class InnerClassExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return isInnerClass(f.getDeclaredClass());
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return isInnerClass(clazz);
|
||||
}
|
||||
|
||||
private boolean isInnerClass(Class<?> clazz) {
|
||||
return clazz.isMemberClass() && !isStatic(clazz);
|
||||
}
|
||||
|
||||
private boolean isStatic(Class<?> clazz) {
|
||||
return (clazz.getModifiers() & Modifier.STATIC) != 0;
|
||||
}
|
||||
}
|
@ -18,6 +18,8 @@ package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore2.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
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A simple implementation of the {@link FieldNamingStrategy2} interface such that it does not
|
||||
* perform any string translation of the incoming field name.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
*
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* JavaFieldNamingPolicy policy = new JavaFieldNamingPolicy();
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("integerField".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* <p>This is the default {@link FieldNamingStrategy2} used by Gson.</p>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JavaFieldNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
||||
return target;
|
||||
}
|
||||
}
|
@ -22,6 +22,11 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.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
|
||||
|
@ -18,6 +18,11 @@ package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* Context for deserialization that is passed to a custom deserializer during invocation of its
|
||||
* {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)}
|
||||
|
@ -18,6 +18,12 @@ package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore2.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
|
||||
@ -61,6 +67,9 @@ import java.lang.reflect.Type;
|
||||
* 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
|
||||
*
|
||||
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Decorators a {@code JsonDeserializer} instance with exception handling. This wrapper class
|
||||
* ensures that a {@code JsonDeserializer} will not propagate any exception other than a
|
||||
* {@link JsonParseException}.
|
||||
*
|
||||
* @param <T> type of the deserializer being wrapped.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
|
||||
|
||||
private final JsonDeserializer<T> delegate;
|
||||
|
||||
/**
|
||||
* Returns a wrapped {@link JsonDeserializer} object that has been decorated with
|
||||
* {@link JsonParseException} handling.
|
||||
*
|
||||
* @param delegate the {@code JsonDeserializer} instance to be wrapped.
|
||||
* @throws IllegalArgumentException if {@code delegate} is {@code null}.
|
||||
*/
|
||||
JsonDeserializerExceptionWrapper(JsonDeserializer<T> delegate) {
|
||||
this.delegate = $Gson$Preconditions.checkNotNull(delegate);
|
||||
}
|
||||
|
||||
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
try {
|
||||
return delegate.deserialize(json, typeOfT, context);
|
||||
} catch (JsonParseException e) {
|
||||
// just rethrow the exception
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// rethrow as a JsonParseException
|
||||
StringBuilder errorMsg = new StringBuilder()
|
||||
.append("The JsonDeserializer ")
|
||||
.append(delegate)
|
||||
.append(" failed to deserialize json object ")
|
||||
.append(json)
|
||||
.append(" given the type ")
|
||||
.append(typeOfT);
|
||||
throw new JsonParseException(errorMsg.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate.toString();
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Definition of a visitor for a JsonElement tree.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
interface JsonElementVisitor {
|
||||
void visitPrimitive(JsonPrimitive primitive) throws IOException;
|
||||
void visitNull() throws IOException;
|
||||
|
||||
void startArray(JsonArray array) throws IOException;
|
||||
void visitArrayMember(JsonArray parent, JsonPrimitive member, boolean isFirst) throws IOException;
|
||||
void visitArrayMember(JsonArray parent, JsonArray member, boolean isFirst) throws IOException;
|
||||
void visitArrayMember(JsonArray parent, JsonObject member, boolean isFirst) throws IOException;
|
||||
void visitNullArrayMember(JsonArray parent, boolean isFirst) throws IOException;
|
||||
void endArray(JsonArray array) throws IOException;
|
||||
|
||||
void startObject(JsonObject object) throws IOException;
|
||||
void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member,
|
||||
boolean isFirst) throws IOException;
|
||||
void visitObjectMember(JsonObject parent, String memberName, JsonArray member,
|
||||
boolean isFirst) throws IOException;
|
||||
void visitObjectMember(JsonObject parent, String memberName, JsonObject member,
|
||||
boolean isFirst) throws IOException;
|
||||
void visitNullObjectMember(JsonObject parent, String memberName,
|
||||
boolean isFirst) throws IOException;
|
||||
void endObject(JsonObject object) throws IOException;
|
||||
}
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* This exception is raised when Gson was unable to read an input stream
|
||||
* or write to one.
|
||||
@ -23,7 +25,6 @@ package com.massivecraft.mcore2.lib.gson;
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public final class JsonIOException extends JsonParseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JsonIOException(String msg) {
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
|
||||
/**
|
||||
* A class representing a Json {@code null} value.
|
||||
*
|
||||
|
@ -16,6 +16,11 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.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
|
||||
|
@ -15,6 +15,11 @@
|
||||
*/
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.LazilyParsedNumber;
|
||||
|
||||
|
@ -18,6 +18,10 @@ package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializer;
|
||||
|
||||
/**
|
||||
* Context for serialization that is passed to a custom serializer during invocation of its
|
||||
* {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method.
|
||||
|
@ -18,6 +18,10 @@ package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
|
||||
/**
|
||||
* Interface representing a custom serializer for Json. You should write a custom serializer, if
|
||||
* you are not happy with the default serialization done by Gson. You will also need to register
|
||||
@ -60,6 +64,9 @@ import java.lang.reflect.Type;
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).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
|
||||
*
|
||||
|
@ -22,6 +22,10 @@ import java.io.StringReader;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
@ -50,7 +54,6 @@ import com.massivecraft.mcore2.lib.gson.stream.MalformedJsonException;
|
||||
* @since 1.4
|
||||
*/
|
||||
public final class JsonStreamParser implements Iterator<JsonElement> {
|
||||
|
||||
private final JsonReader parser;
|
||||
private final Object lock;
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonParseException;
|
||||
|
||||
/**
|
||||
* This exception is raised when Gson attempts to read (or write) a malformed
|
||||
* JSON element.
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
|
||||
/**
|
||||
* Defines the expected format for a {@code long} or {@code Long} type when its serialized.
|
||||
*
|
||||
@ -31,20 +34,22 @@ public enum LongSerializationPolicy {
|
||||
* would be:
|
||||
* {@code {"f":123}}.
|
||||
*/
|
||||
DEFAULT(new DefaultStrategy()),
|
||||
DEFAULT() {
|
||||
public JsonElement serialize(Long value) {
|
||||
return new JsonPrimitive(value);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Serializes a long value as a quoted string. For example, assume an object has a long field
|
||||
* named "f" then the serialized output would be:
|
||||
* {@code {"f":"123"}}.
|
||||
*/
|
||||
STRING(new StringStrategy());
|
||||
|
||||
private final Strategy strategy;
|
||||
|
||||
private LongSerializationPolicy(Strategy strategy) {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
STRING() {
|
||||
public JsonElement serialize(Long value) {
|
||||
return new JsonPrimitive(String.valueOf(value));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize this {@code value} using this serialization policy.
|
||||
@ -52,23 +57,5 @@ public enum LongSerializationPolicy {
|
||||
* @param value the long value to be serialized into a {@link JsonElement}
|
||||
* @return the serialized version of {@code value}
|
||||
*/
|
||||
public JsonElement serialize(Long value) {
|
||||
return strategy.serialize(value);
|
||||
}
|
||||
|
||||
private interface Strategy {
|
||||
JsonElement serialize(Long value);
|
||||
}
|
||||
|
||||
private static class DefaultStrategy implements Strategy {
|
||||
public JsonElement serialize(Long value) {
|
||||
return new JsonPrimitive(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringStrategy implements Strategy {
|
||||
public JsonElement serialize(Long value) {
|
||||
return new JsonPrimitive(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
public abstract JsonElement serialize(Long value);
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
|
||||
* lower case letters and are separated by a particular {@code separatorString}.
|
||||
*
|
||||
*<p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class StringWrapper {
|
||||
* public String AStringField = "abcd";
|
||||
* }
|
||||
*
|
||||
* LowerCamelCaseSeparatorNamingPolicy policy = new LowerCamelCaseSeparatorNamingPolicy("_");
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("AStringField"));
|
||||
*
|
||||
* assert("a_string_field".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class LowerCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
|
||||
|
||||
public LowerCamelCaseSeparatorNamingPolicy(String separatorString) {
|
||||
super(new CamelCaseSeparatorNamingPolicy(separatorString), new LowerCaseNamingPolicy());
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
|
||||
* lower case letters.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* LowerCaseNamingPolicy policy = new LowerCaseNamingPolicy();
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("integerfield".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class LowerCaseNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType,
|
||||
Collection<Annotation> annotations) {
|
||||
return target.toLowerCase();
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implementation of the {@link Cache} interface that evict objects from the cache using an
|
||||
* LRU (least recently used) algorithm. Object start getting evicted from the cache once the
|
||||
* {@code maxCapacity} is reached.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class LruCache<K, V> extends LinkedHashMap<K, V> implements Cache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final int maxCapacity;
|
||||
|
||||
public LruCache(int maxCapacity) {
|
||||
super(maxCapacity, 0.7F, true);
|
||||
this.maxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
public synchronized void addElement(K key, V value) {
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
public synchronized V getElement(K key) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
|
||||
return size() > maxCapacity;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* Exclude fields based on particular field modifiers. For a list of possible
|
||||
* modifiers, see {@link java.lang.reflect.Modifier}.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ModifierBasedExclusionStrategy implements ExclusionStrategy {
|
||||
private final Collection<Integer> modifiers;
|
||||
|
||||
public ModifierBasedExclusionStrategy(int... modifiers) {
|
||||
this.modifiers = new HashSet<Integer>();
|
||||
if (modifiers != null) {
|
||||
for (int modifier : modifiers) {
|
||||
this.modifiers.add(modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
for (int modifier : modifiers) {
|
||||
if (f.hasModifier(modifier)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names begins with
|
||||
* an upper case letter.
|
||||
*
|
||||
*<p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class StringWrapper {
|
||||
* public String stringField = "abcd";
|
||||
* public String _stringField = "efg";
|
||||
* }
|
||||
*
|
||||
* ModifyFirstLetterNamingPolicy policy =
|
||||
* new ModifyFirstLetterNamingPolicy(LetterModifier.UPPER);
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("stringField"));
|
||||
*
|
||||
* assert("StringField".equals(translatedFieldName));
|
||||
*
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("_stringField"));
|
||||
*
|
||||
* assert("_StringField".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
public enum LetterModifier {
|
||||
UPPER,
|
||||
LOWER;
|
||||
}
|
||||
|
||||
private final LetterModifier letterModifier;
|
||||
|
||||
/**
|
||||
* Creates a new ModifyFirstLetterNamingPolicy that will either modify the first letter of the
|
||||
* target name to either UPPER case or LOWER case depending on the {@code modifier} parameter.
|
||||
*
|
||||
* @param modifier the type of modification that should be performed
|
||||
* @throws IllegalArgumentException if {@code modifier} is null
|
||||
*/
|
||||
ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
|
||||
this.letterModifier = $Gson$Preconditions.checkNotNull(modifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType,
|
||||
Collection<Annotation> annotations) {
|
||||
StringBuilder fieldNameBuilder = new StringBuilder();
|
||||
int index = 0;
|
||||
char firstCharacter = target.charAt(index);
|
||||
|
||||
while (index < target.length() - 1) {
|
||||
if (Character.isLetter(firstCharacter)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fieldNameBuilder.append(firstCharacter);
|
||||
firstCharacter = target.charAt(++index);
|
||||
}
|
||||
|
||||
if (index == target.length()) {
|
||||
return fieldNameBuilder.toString();
|
||||
}
|
||||
|
||||
boolean capitalizeFirstLetter = (letterModifier == LetterModifier.UPPER);
|
||||
if (capitalizeFirstLetter && !Character.isUpperCase(firstCharacter)) {
|
||||
String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), target, ++index);
|
||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
||||
} else if (!capitalizeFirstLetter && Character.isUpperCase(firstCharacter)) {
|
||||
String modifiedTarget = modifyString(Character.toLowerCase(firstCharacter), target, ++index);
|
||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
||||
} else {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
|
||||
return (indexOfSubstring < srcString.length())
|
||||
? firstCharacter + srcString.substring(indexOfSubstring)
|
||||
: String.valueOf(firstCharacter);
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A mechanism for providing custom field naming in Gson. This allows the client code to translate
|
||||
* field names into a particular convention that is not supported as a normal Java field
|
||||
* declaration rules. For example, Java does not support "-" characters in a field name.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 {
|
||||
|
||||
public final String translateName(FieldAttributes f) {
|
||||
return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the specific string translation.
|
||||
*
|
||||
* @param target the string object that will be manipulation/translated
|
||||
* @param fieldType the actual type value of the field
|
||||
* @param annotations the annotations set on the field
|
||||
* @return the translated field name
|
||||
*/
|
||||
protected abstract String translateName(String target, Type fieldType, Collection<Annotation> annotations);
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the
|
||||
* {@link com.massivecraft.mcore2.lib.gson.annotations.SerializedName} annotation is applied to a
|
||||
* field then this strategy will translate the name to the {@code
|
||||
* serializedName.value()}; otherwise it delegates to the wrapped
|
||||
* {@link FieldNamingStrategy2}.
|
||||
*
|
||||
* <p>
|
||||
* NOTE: this class performs JSON field name validation for any of the fields
|
||||
* marked with an {@code @SerializedName} annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see SerializedName
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 {
|
||||
private final FieldNamingStrategy2 delegate;
|
||||
|
||||
SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String translateName(FieldAttributes f) {
|
||||
SerializedName serializedName = f.getAnnotation(SerializedName.class);
|
||||
return serializedName == null ? delegate.translateName(f) : serializedName.value();
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* A data object that stores attributes of a field.
|
||||
*
|
||||
* <p>This class is immutable; therefore, it can be safely shared across threads.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
final class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
|
||||
private final boolean skipSyntheticFields;
|
||||
|
||||
SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) {
|
||||
this.skipSyntheticFields = skipSyntheticFields;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return skipSyntheticFields && f.isSynthetic();
|
||||
}
|
||||
|
||||
}
|
149
src/com/massivecraft/mcore2/lib/gson/TreeTypeAdapter.java
Normal file
149
src/com/massivecraft/mcore2/lib/gson/TreeTypeAdapter.java
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonDeserializer;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSerializer;
|
||||
import com.massivecraft.mcore2.lib.gson.TreeTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.GsonInternalAccess;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the
|
||||
* tree adapter may be serialization-only or deserialization-only, this class
|
||||
* has a facility to lookup a delegate type adapter on demand.
|
||||
*/
|
||||
final class TreeTypeAdapter<T> extends TypeAdapter<T> {
|
||||
private final JsonSerializer<T> serializer;
|
||||
private final JsonDeserializer<T> deserializer;
|
||||
private final Gson gson;
|
||||
private final TypeToken<T> typeToken;
|
||||
private final TypeAdapterFactory skipPast;
|
||||
|
||||
/** The delegate is lazily created because it may not be needed, and creating it may fail. */
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
private TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
|
||||
Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
|
||||
this.serializer = serializer;
|
||||
this.deserializer = deserializer;
|
||||
this.gson = gson;
|
||||
this.typeToken = typeToken;
|
||||
this.skipPast = skipPast;
|
||||
}
|
||||
|
||||
@Override public T read(JsonReader in) throws IOException {
|
||||
if (deserializer == null) {
|
||||
return delegate().read(in);
|
||||
}
|
||||
JsonElement value = Streams.parse(in);
|
||||
if (value.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter out, T value) throws IOException {
|
||||
if (serializer == null) {
|
||||
delegate().write(out, value);
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext);
|
||||
Streams.write(tree, out);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = GsonInternalAccess.INSTANCE.getNextAdapter(gson, skipPast, typeToken));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new factory that will match each type against {@code exactType}.
|
||||
*/
|
||||
public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) {
|
||||
return new SingleTypeFactory(typeAdapter, exactType, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new factory that will match each type and its raw type against
|
||||
* {@code exactType}.
|
||||
*/
|
||||
public static TypeAdapterFactory newFactoryWithMatchRawType(
|
||||
TypeToken<?> exactType, Object typeAdapter) {
|
||||
// only bother matching raw types if exact type is a raw type
|
||||
boolean matchRawType = exactType.getType() == exactType.getRawType();
|
||||
return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new factory that will match each type's raw type for assignability
|
||||
* to {@code hierarchyType}.
|
||||
*/
|
||||
public static TypeAdapterFactory newTypeHierarchyFactory(
|
||||
Class<?> hierarchyType, Object typeAdapter) {
|
||||
return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);
|
||||
}
|
||||
|
||||
private static class SingleTypeFactory implements TypeAdapterFactory {
|
||||
private final TypeToken<?> exactType;
|
||||
private final boolean matchRawType;
|
||||
private final Class<?> hierarchyType;
|
||||
private final JsonSerializer<?> serializer;
|
||||
private final JsonDeserializer<?> deserializer;
|
||||
|
||||
private SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType,
|
||||
Class<?> hierarchyType) {
|
||||
serializer = typeAdapter instanceof JsonSerializer
|
||||
? (JsonSerializer<?>) typeAdapter
|
||||
: null;
|
||||
deserializer = typeAdapter instanceof JsonDeserializer
|
||||
? (JsonDeserializer<?>) typeAdapter
|
||||
: null;
|
||||
$Gson$Preconditions.checkArgument(serializer != null || deserializer != null);
|
||||
this.exactType = exactType;
|
||||
this.matchRawType = matchRawType;
|
||||
this.hierarchyType = hierarchyType;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // guarded by typeToken.equals() call
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
boolean matches = exactType != null
|
||||
? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType()
|
||||
: hierarchyType.isAssignableFrom(type.getRawType());
|
||||
return matches
|
||||
? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer,
|
||||
(JsonDeserializer<T>) deserializer, gson, type, this)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
290
src/com/massivecraft/mcore2/lib/gson/TypeAdapter.java
Normal file
290
src/com/massivecraft/mcore2/lib/gson/TypeAdapter.java
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.GsonBuilder;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonTreeReader;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonTreeWriter;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Converts Java objects to and from JSON.
|
||||
*
|
||||
* <h3>Defining a type's JSON form</h3>
|
||||
* By default Gson converts application classes to JSON using its built-in type
|
||||
* adapters. If Gson's default JSON conversion isn't appropriate for a type,
|
||||
* extend this class to customize the conversion. Here's an example of a type
|
||||
* adapter for an (X,Y) coordinate point: <pre> {@code
|
||||
*
|
||||
* public class PointAdapter extends TypeAdapter<Point> {
|
||||
* public Point read(JsonReader reader) throws IOException {
|
||||
* if (reader.peek() == JsonToken.NULL) {
|
||||
* reader.nextNull();
|
||||
* return null;
|
||||
* }
|
||||
* String xy = reader.nextString();
|
||||
* String[] parts = xy.split(",");
|
||||
* int x = Integer.parseInt(parts[0]);
|
||||
* int y = Integer.parseInt(parts[1]);
|
||||
* return new Point(x, y);
|
||||
* }
|
||||
* public void write(JsonWriter writer, Point value) throws IOException {
|
||||
* if (value == null) {
|
||||
* writer.nullValue();
|
||||
* return;
|
||||
* }
|
||||
* String xy = value.getX() + "," + value.getY();
|
||||
* writer.value(xy);
|
||||
* }
|
||||
* }}</pre>
|
||||
* With this type adapter installed, Gson will convert {@code Points} to JSON as
|
||||
* strings like {@code "5,8"} rather than objects like {@code {"x":5,"y":8}}. In
|
||||
* this case the type adapter binds a rich Java class to a compact JSON value.
|
||||
*
|
||||
* <p>The {@link #read(JsonReader) read()} method must read exactly one value
|
||||
* and {@link #write(JsonWriter,Object) write()} must write exactly one value.
|
||||
* For primitive types this is means readers should make exactly one call to
|
||||
* {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code
|
||||
* nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make
|
||||
* exactly one call to one of <code>value()</code> or <code>nullValue()</code>.
|
||||
* For arrays, type adapters should start with a call to {@code beginArray()},
|
||||
* convert all elements, and finish with a call to {@code endArray()}. For
|
||||
* objects, they should start with {@code beginObject()}, convert the object,
|
||||
* and finish with {@code endObject()}. Failing to convert a value or converting
|
||||
* too many values may cause the application to crash.
|
||||
*
|
||||
* <p>Type adapters should be prepared to read null from the stream and write it
|
||||
* to the stream. Alternatively, they should use {@link #nullSafe()} method while
|
||||
* registering the type adapter with Gson. If your {@code Gson} instance
|
||||
* has been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be
|
||||
* written to the final document. Otherwise the value (and the corresponding name
|
||||
* when writing to a JSON object) will be omitted automatically. In either case
|
||||
* your type adapter must handle null.
|
||||
*
|
||||
* <p>To use a custom type adapter with Gson, you must <i>register</i> it with a
|
||||
* {@link GsonBuilder}: <pre> {@code
|
||||
*
|
||||
* GsonBuilder builder = new GsonBuilder();
|
||||
* builder.registerTypeAdapter(Point.class, new PointAdapter());
|
||||
* // if PointAdapter didn't check for nulls in its read/write methods, you should instead use
|
||||
* // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
|
||||
* ...
|
||||
* Gson gson = builder.create();
|
||||
* }</pre>
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
// non-Javadoc:
|
||||
//
|
||||
// <h3>JSON Conversion</h3>
|
||||
// <p>A type adapter registered with Gson is automatically invoked while serializing
|
||||
// or deserializing JSON. However, you can also use type adapters directly to serialize
|
||||
// and deserialize JSON. Here is an example for deserialization: <pre> {@code
|
||||
//
|
||||
// String json = "{'origin':'0,0','points':['1,2','3,4']}";
|
||||
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
|
||||
// Graph graph = graphAdapter.fromJson(json);
|
||||
// }</pre>
|
||||
// And an example for serialization: <pre> {@code
|
||||
//
|
||||
// Graph graph = new Graph(...);
|
||||
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
|
||||
// String json = graphAdapter.toJson(graph);
|
||||
// }</pre>
|
||||
//
|
||||
// <p>Type adapters are <strong>type-specific</strong>. For example, a {@code
|
||||
// TypeAdapter<Date>} can convert {@code Date} instances to JSON and JSON to
|
||||
// instances of {@code Date}, but cannot convert any other types.
|
||||
//
|
||||
public abstract class TypeAdapter<T> {
|
||||
|
||||
/**
|
||||
* Writes one JSON value (an array, object, string, number, boolean or null)
|
||||
* for {@code value}.
|
||||
*
|
||||
* @param value the Java object to write. May be null.
|
||||
*/
|
||||
public abstract void write(JsonWriter out, T value) throws IOException;
|
||||
|
||||
/**
|
||||
* Converts {@code value} to a JSON document and writes it to {@code out}.
|
||||
* Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson}
|
||||
* method, this write is strict. Create a {@link
|
||||
* JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
|
||||
* {@link #write(com.massivecraft.mcore2.lib.gson.stream.JsonWriter, Object)} for lenient
|
||||
* writing.
|
||||
*
|
||||
* @param value the Java object to convert. May be null.
|
||||
*/
|
||||
/*public*/ final void toJson(Writer out, T value) throws IOException {
|
||||
JsonWriter writer = new JsonWriter(out);
|
||||
write(writer, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* This wrapper method is used to make a type adapter null tolerant. In general, a
|
||||
* type adapter is required to handle nulls in write and read methods. Here is how this
|
||||
* is typically done:<br>
|
||||
* <pre> {@code
|
||||
*
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
|
||||
* new TypeAdapter<Foo>() {
|
||||
* public Foo read(JsonReader in) throws IOException {
|
||||
* if (in.peek() == JsonToken.NULL) {
|
||||
* in.nextNull();
|
||||
* return null;
|
||||
* }
|
||||
* // read a Foo from in and return it
|
||||
* }
|
||||
* public void write(JsonWriter out, Foo src) throws IOException {
|
||||
* if (src == null) {
|
||||
* out.nullValue();
|
||||
* return;
|
||||
* }
|
||||
* // write src as JSON to out
|
||||
* }
|
||||
* }).create();
|
||||
* }</pre>
|
||||
* You can avoid this boilerplate handling of nulls by wrapping your type adapter with
|
||||
* this method. Here is how we will rewrite the above example:
|
||||
* <pre> {@code
|
||||
*
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
|
||||
* new TypeAdapter<Foo>() {
|
||||
* public Foo read(JsonReader in) throws IOException {
|
||||
* // read a Foo from in and return it
|
||||
* }
|
||||
* public void write(JsonWriter out, Foo src) throws IOException {
|
||||
* // write src as JSON to out
|
||||
* }
|
||||
* }.nullSafe()).create();
|
||||
* }</pre>
|
||||
* Note that we didn't need to check for nulls in our type adapter after we used nullSafe.
|
||||
*/
|
||||
public final TypeAdapter<T> nullSafe() {
|
||||
return new TypeAdapter<T>() {
|
||||
@Override public void write(JsonWriter out, T value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
} else {
|
||||
TypeAdapter.this.write(out, value);
|
||||
}
|
||||
}
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
return TypeAdapter.this.read(reader);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@code value} to a JSON document. Unlike Gson's similar {@link
|
||||
* Gson#toJson(Object) toJson} method, this write is strict. Create a {@link
|
||||
* JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
|
||||
* {@link #write(com.massivecraft.mcore2.lib.gson.stream.JsonWriter, Object)} for lenient
|
||||
* writing.
|
||||
*
|
||||
* @param value the Java object to convert. May be null.
|
||||
*/
|
||||
/*public*/ final String toJson(T value) throws IOException {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
toJson(stringWriter, value);
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@code value} to a JSON tree.
|
||||
*
|
||||
* @param value the Java object to convert. May be null.
|
||||
* @return the converted JSON tree. May be {@link JsonNull}.
|
||||
*/
|
||||
/*public*/ final JsonElement toJsonTree(T value) {
|
||||
try {
|
||||
JsonTreeWriter jsonWriter = new JsonTreeWriter();
|
||||
jsonWriter.setLenient(true);
|
||||
write(jsonWriter, value);
|
||||
return jsonWriter.get();
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads one JSON value (an array, object, string, number, boolean or null)
|
||||
* and converts it to a Java object. Returns the converted object.
|
||||
*
|
||||
* @return the converted Java object. May be null.
|
||||
*/
|
||||
public abstract T read(JsonReader in) throws IOException;
|
||||
|
||||
/**
|
||||
* Converts the JSON document in {@code in} to a Java object. Unlike Gson's
|
||||
* similar {@link Gson#fromJson(java.io.Reader, Class) fromJson} method, this
|
||||
* read is strict. Create a {@link JsonReader#setLenient(boolean) lenient}
|
||||
* {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading.
|
||||
*
|
||||
* @return the converted Java object. May be null.
|
||||
*/
|
||||
/*public*/ final T fromJson(Reader in) throws IOException {
|
||||
JsonReader reader = new JsonReader(in);
|
||||
reader.setLenient(true); // TODO: non-lenient?
|
||||
return read(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the JSON document in {@code json} to a Java object. Unlike Gson's
|
||||
* similar {@link Gson#fromJson(String, Class) fromJson} method, this read is
|
||||
* strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code
|
||||
* JsonReader} and call {@link #read(JsonReader)} for lenient reading.
|
||||
*
|
||||
* @return the converted Java object. May be null.
|
||||
*/
|
||||
/*public*/ final T fromJson(String json) throws IOException {
|
||||
return fromJson(new StringReader(json));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts {@code jsonTree} to a Java object.
|
||||
*
|
||||
* @param jsonTree the Java object to convert. May be {@link JsonNull}.
|
||||
*/
|
||||
/*public*/ final T fromJsonTree(JsonElement jsonTree) {
|
||||
try {
|
||||
JsonReader jsonReader = new JsonTreeReader(jsonTree);
|
||||
jsonReader.setLenient(true);
|
||||
return read(jsonReader);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
172
src/com/massivecraft/mcore2/lib/gson/TypeAdapterFactory.java
Normal file
172
src/com/massivecraft/mcore2/lib/gson/TypeAdapterFactory.java
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Creates type adapters for set of related types. Type adapter factories are
|
||||
* most useful when several types share similar structure in their JSON form.
|
||||
*
|
||||
* <h3>Example: Converting enums to lowercase</h3>
|
||||
* In this example, we implement a factory that creates type adapters for all
|
||||
* enums. The type adapters will write enums in lowercase, despite the fact
|
||||
* that they're defined in {@code CONSTANT_CASE} in the corresponding Java
|
||||
* model: <pre> {@code
|
||||
*
|
||||
* public class LowercaseEnumTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
* Class<T> rawType = (Class<T>) type.getRawType();
|
||||
* if (!rawType.isEnum()) {
|
||||
* return null;
|
||||
* }
|
||||
*
|
||||
* final Map<String, T> lowercaseToConstant = new HashMap<String, T>();
|
||||
* for (T constant : rawType.getEnumConstants()) {
|
||||
* lowercaseToConstant.put(toLowercase(constant), constant);
|
||||
* }
|
||||
*
|
||||
* return new TypeAdapter<T>() {
|
||||
* public void write(JsonWriter out, T value) throws IOException {
|
||||
* if (value == null) {
|
||||
* out.nullValue();
|
||||
* } else {
|
||||
* out.value(toLowercase(value));
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public T read(JsonReader reader) throws IOException {
|
||||
* if (reader.peek() == JsonToken.NULL) {
|
||||
* reader.nextNull();
|
||||
* return null;
|
||||
* } else {
|
||||
* return lowercaseToConstant.get(reader.nextString());
|
||||
* }
|
||||
* }
|
||||
* };
|
||||
* }
|
||||
*
|
||||
* private String toLowercase(Object o) {
|
||||
* return o.toString().toLowerCase(Locale.US);
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Type adapter factories select which types they provide type adapters
|
||||
* for. If a factory cannot support a given type, it must return null when
|
||||
* that type is passed to {@link #create}. Factories should expect {@code
|
||||
* create()} to be called on them for many types and should return null for
|
||||
* most of those types. In the above example the factory returns null for
|
||||
* calls to {@code create()} where {@code type} is not an enum.
|
||||
*
|
||||
* <p>A factory is typically called once per type, but the returned type
|
||||
* adapter may be used many times. It is most efficient to do expensive work
|
||||
* like reflection in {@code create()} so that the type adapter's {@code
|
||||
* read()} and {@code write()} methods can be very fast. In this example the
|
||||
* mapping from lowercase name to enum value is computed eagerly.
|
||||
*
|
||||
* <p>As with type adapters, factories must be <i>registered</i> with a {@link
|
||||
* com.massivecraft.mcore2.lib.gson.GsonBuilder} for them to take effect: <pre> {@code
|
||||
*
|
||||
* GsonBuilder builder = new GsonBuilder();
|
||||
* builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory());
|
||||
* ...
|
||||
* Gson gson = builder.create();
|
||||
* }</pre>
|
||||
* If multiple factories support the same type, the factory registered earlier
|
||||
* takes precedence.
|
||||
*
|
||||
* <h3>Example: composing other type adapters</h3>
|
||||
* In this example we implement a factory for Guava's {@code Multiset}
|
||||
* collection type. The factory can be used to create type adapters for
|
||||
* multisets of any element type: the type adapter for {@code
|
||||
* Multiset<String>} is different from the type adapter for {@code
|
||||
* Multiset<URL>}.
|
||||
*
|
||||
* <p>The type adapter <i>delegates</i> to another type adapter for the
|
||||
* multiset elements. It figures out the element type by reflecting on the
|
||||
* multiset's type token. A {@code Gson} is passed in to {@code create} for
|
||||
* just this purpose: <pre> {@code
|
||||
*
|
||||
* public class MultisetTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
* Type type = typeToken.getType();
|
||||
* if (typeToken.getRawType() != Multiset.class
|
||||
* || !(type instanceof ParameterizedType)) {
|
||||
* return null;
|
||||
* }
|
||||
*
|
||||
* Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||
* TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
|
||||
* return (TypeAdapter<T>) newMultisetAdapter(elementAdapter);
|
||||
* }
|
||||
*
|
||||
* private <E> TypeAdapter<Multiset<E>> newMultisetAdapter(
|
||||
* final TypeAdapter<E> elementAdapter) {
|
||||
* return new TypeAdapter<Multiset<E>>() {
|
||||
* public void write(JsonWriter out, Multiset<E> value) throws IOException {
|
||||
* if (value == null) {
|
||||
* out.nullValue();
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* out.beginArray();
|
||||
* for (Multiset.Entry<E> entry : value.entrySet()) {
|
||||
* out.value(entry.getCount());
|
||||
* elementAdapter.write(out, entry.getElement());
|
||||
* }
|
||||
* out.endArray();
|
||||
* }
|
||||
*
|
||||
* public Multiset<E> read(JsonReader in) throws IOException {
|
||||
* if (in.peek() == JsonToken.NULL) {
|
||||
* in.nextNull();
|
||||
* return null;
|
||||
* }
|
||||
*
|
||||
* Multiset<E> result = LinkedHashMultiset.create();
|
||||
* in.beginArray();
|
||||
* while (in.hasNext()) {
|
||||
* int count = in.nextInt();
|
||||
* E element = elementAdapter.read(in);
|
||||
* result.add(element, count);
|
||||
* }
|
||||
* in.endArray();
|
||||
* return result;
|
||||
* }
|
||||
* };
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
* Delegating from one type adapter to another is extremely powerful; it's
|
||||
* the foundation of how Gson converts Java objects and collections. Whenever
|
||||
* possible your factory should retrieve its delegate type adapter in the
|
||||
* {@code create()} method; this ensures potentially-expensive type adapter
|
||||
* creation happens only once.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public interface TypeAdapterFactory {
|
||||
|
||||
/**
|
||||
* Returns a type adapter for {@code type}, or null if this factory doesn't
|
||||
* support {@code type}.
|
||||
*/
|
||||
<T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names consist of mixed
|
||||
* case letters starting with a capital and are separated by a particular
|
||||
* {@code separatorString}.
|
||||
*
|
||||
*<p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class StringWrapper {
|
||||
* public String AStringField = "abcd";
|
||||
* }
|
||||
*
|
||||
* UpperCamelCaseSeparatorNamingPolicy policy = new UpperCamelCaseSeparatorNamingPolicy("_");
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(StringWrapper.class.getField("AStringField"));
|
||||
*
|
||||
* assert("A_String_Field".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class UpperCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
|
||||
|
||||
public UpperCamelCaseSeparatorNamingPolicy(String separatorString) {
|
||||
super(new CamelCaseSeparatorNamingPolicy(separatorString),
|
||||
new ModifyFirstLetterNamingPolicy(ModifyFirstLetterNamingPolicy.LetterModifier.UPPER));
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
|
||||
* upper case letters.
|
||||
*
|
||||
* <p>The following is an example:</p>
|
||||
* <pre>
|
||||
* class IntWrapper {
|
||||
* public int integerField = 0;
|
||||
* }
|
||||
*
|
||||
* UpperCaseNamingPolicy policy = new UpperCaseNamingPolicy();
|
||||
* String translatedFieldName =
|
||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
||||
*
|
||||
* assert("INTEGERFIELD".equals(translatedFieldName));
|
||||
* </pre>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class UpperCaseNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
|
||||
@Override
|
||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
||||
return target.toUpperCase();
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
/**
|
||||
* Class contain all constants for versioning support.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class VersionConstants {
|
||||
// Prevent instantiation
|
||||
private VersionConstants() { }
|
||||
|
||||
static final double IGNORE_VERSIONS = -1D;
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Since;
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Until;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
|
||||
/**
|
||||
* This strategy will exclude any files and/or class that are passed the
|
||||
* {@link #version} value.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class VersionExclusionStrategy implements ExclusionStrategy {
|
||||
private final double version;
|
||||
|
||||
VersionExclusionStrategy(double version) {
|
||||
$Gson$Preconditions.checkArgument(version >= 0.0D);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return !isValidVersion(f.getAnnotation(Since.class), f.getAnnotation(Until.class));
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class));
|
||||
}
|
||||
|
||||
private boolean isValidVersion(Since since, Until until) {
|
||||
return (isValidSince(since) && isValidUntil(until));
|
||||
}
|
||||
|
||||
private boolean isValidSince(Since annotation) {
|
||||
if (annotation != null) {
|
||||
double annotationVersion = annotation.value();
|
||||
if (annotationVersion > version) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidUntil(Until annotation) {
|
||||
if (annotation != null) {
|
||||
double annotationVersion = annotation.value();
|
||||
if (annotationVersion <= version) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -42,10 +42,4 @@ public final class $Gson$Preconditions {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -269,14 +269,6 @@ public final class $Gson$Types {
|
||||
$Gson$Types.getGenericSupertype(context, contextRawType, supertype));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this type is an array.
|
||||
*/
|
||||
public static boolean isArray(Type type) {
|
||||
return type instanceof GenericArrayType
|
||||
|| (type instanceof Class && ((Class<?>) type).isArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component type of this array type.
|
||||
* @throws ClassCastException if this type is not an array.
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ObjectConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.UnsafeAllocator;
|
||||
import com.massivecraft.mcore2.lib.gson.InstanceCreator;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
|
||||
@ -24,6 +26,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
@ -37,14 +40,14 @@ import java.util.TreeSet;
|
||||
* Returns a function that can construct an instance of a requested type.
|
||||
*/
|
||||
public final class ConstructorConstructor {
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators;
|
||||
private final Map<Type, InstanceCreator<?>> instanceCreators;
|
||||
|
||||
public ConstructorConstructor(ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) {
|
||||
public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {
|
||||
this.instanceCreators = instanceCreators;
|
||||
}
|
||||
|
||||
public ConstructorConstructor() {
|
||||
this(new ParameterizedTypeHandlerMap<InstanceCreator<?>>());
|
||||
this(Collections.<Type, InstanceCreator<?>>emptyMap());
|
||||
}
|
||||
|
||||
public <T> ObjectConstructor<T> getConstructor(TypeToken<T> typeToken) {
|
||||
@ -54,8 +57,7 @@ public final class ConstructorConstructor {
|
||||
// first try an instance creator
|
||||
|
||||
@SuppressWarnings("unchecked") // types must agree
|
||||
final InstanceCreator<T> creator
|
||||
= (InstanceCreator<T>) instanceCreators.getHandlerFor(type, false);
|
||||
final InstanceCreator<T> creator = (InstanceCreator<T>) instanceCreators.get(type);
|
||||
if (creator != null) {
|
||||
return new ObjectConstructor<T>() {
|
||||
public T construct() {
|
||||
|
254
src/com/massivecraft/mcore2/lib/gson/internal/Excluder.java
Normal file
254
src/com/massivecraft/mcore2/lib/gson/internal/Excluder.java
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Excluder;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.GsonInternalAccess;
|
||||
import com.massivecraft.mcore2.lib.gson.ExclusionStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.FieldAttributes;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Expose;
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Since;
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.Until;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class selects which fields and types to omit. It is configurable,
|
||||
* supporting version attributes {@link Since} and {@link Until}, modifiers,
|
||||
* synthetic fields, anonymous and local classes, inner classes, and fields with
|
||||
* the {@link Expose} annotation.
|
||||
*
|
||||
* <p>This class is a type adapter factory; types that are excluded will be
|
||||
* adapted to null. It may delegate to another type adapter if only one
|
||||
* direction is excluded.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public final class Excluder implements TypeAdapterFactory, Cloneable {
|
||||
private static final double IGNORE_VERSIONS = -1.0d;
|
||||
public static final Excluder DEFAULT = new Excluder();
|
||||
|
||||
private double version = IGNORE_VERSIONS;
|
||||
private int modifiers = Modifier.TRANSIENT | Modifier.STATIC;
|
||||
private boolean serializeInnerClasses = true;
|
||||
private boolean requireExpose;
|
||||
private List<ExclusionStrategy> serializationStrategies = Collections.emptyList();
|
||||
private List<ExclusionStrategy> deserializationStrategies = Collections.emptyList();
|
||||
|
||||
@Override protected Excluder clone() {
|
||||
try {
|
||||
return (Excluder) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public Excluder withVersion(double ignoreVersionsAfter) {
|
||||
Excluder result = clone();
|
||||
result.version = ignoreVersionsAfter;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Excluder withModifiers(int... modifiers) {
|
||||
Excluder result = clone();
|
||||
result.modifiers = 0;
|
||||
for (int modifier : modifiers) {
|
||||
result.modifiers |= modifier;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Excluder disableInnerClassSerialization() {
|
||||
Excluder result = clone();
|
||||
result.serializeInnerClasses = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Excluder excludeFieldsWithoutExposeAnnotation() {
|
||||
Excluder result = clone();
|
||||
result.requireExpose = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
|
||||
boolean serialization, boolean deserialization) {
|
||||
Excluder result = clone();
|
||||
if (serialization) {
|
||||
result.serializationStrategies = new ArrayList<ExclusionStrategy>(serializationStrategies);
|
||||
result.serializationStrategies.add(exclusionStrategy);
|
||||
}
|
||||
if (deserialization) {
|
||||
result.deserializationStrategies
|
||||
= new ArrayList<ExclusionStrategy>(deserializationStrategies);
|
||||
result.deserializationStrategies.add(exclusionStrategy);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
|
||||
Class<?> rawType = type.getRawType();
|
||||
final boolean skipSerialize = excludeClass(rawType, true);
|
||||
final boolean skipDeserialize = excludeClass(rawType, false);
|
||||
|
||||
if (!skipSerialize && !skipDeserialize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
/** The delegate is lazily created because it may not be needed, and creating it may fail. */
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
@Override public T read(JsonReader in) throws IOException {
|
||||
if (skipDeserialize) {
|
||||
in.skipValue();
|
||||
return null;
|
||||
}
|
||||
return delegate().read(in);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter out, T value) throws IOException {
|
||||
if (skipSerialize) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
delegate().write(out, value);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = GsonInternalAccess.INSTANCE.getNextAdapter(gson, Excluder.this, type));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public boolean excludeField(Field field, boolean serialize) {
|
||||
if ((modifiers & field.getModifiers()) != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (version != Excluder.IGNORE_VERSIONS
|
||||
&& !isValidVersion(field.getAnnotation(Since.class), field.getAnnotation(Until.class))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (field.isSynthetic()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (requireExpose) {
|
||||
Expose annotation = field.getAnnotation(Expose.class);
|
||||
if (annotation == null || (serialize ? !annotation.serialize() : !annotation.deserialize())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!serializeInnerClasses && isInnerClass(field.getType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isAnonymousOrLocal(field.getType())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
|
||||
if (!list.isEmpty()) {
|
||||
FieldAttributes fieldAttributes = new FieldAttributes(field);
|
||||
for (ExclusionStrategy exclusionStrategy : list) {
|
||||
if (exclusionStrategy.shouldSkipField(fieldAttributes)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean excludeClass(Class<?> clazz, boolean serialize) {
|
||||
if (version != Excluder.IGNORE_VERSIONS
|
||||
&& !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!serializeInnerClasses && isInnerClass(clazz)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isAnonymousOrLocal(clazz)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
|
||||
for (ExclusionStrategy exclusionStrategy : list) {
|
||||
if (exclusionStrategy.shouldSkipClass(clazz)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAnonymousOrLocal(Class<?> clazz) {
|
||||
return !Enum.class.isAssignableFrom(clazz)
|
||||
&& (clazz.isAnonymousClass() || clazz.isLocalClass());
|
||||
}
|
||||
|
||||
private boolean isInnerClass(Class<?> clazz) {
|
||||
return clazz.isMemberClass() && !isStatic(clazz);
|
||||
}
|
||||
|
||||
private boolean isStatic(Class<?> clazz) {
|
||||
return (clazz.getModifiers() & Modifier.STATIC) != 0;
|
||||
}
|
||||
|
||||
private boolean isValidVersion(Since since, Until until) {
|
||||
return isValidSince(since) && isValidUntil(until);
|
||||
}
|
||||
|
||||
private boolean isValidSince(Since annotation) {
|
||||
if (annotation != null) {
|
||||
double annotationVersion = annotation.value();
|
||||
if (annotationVersion > version) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidUntil(Until annotation) {
|
||||
if (annotation != null) {
|
||||
double annotationVersion = annotation.value();
|
||||
if (annotationVersion <= version) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.GsonInternalAccess;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Internal-only APIs of Gson available only to other classes in Gson.
|
||||
*/
|
||||
public abstract class GsonInternalAccess {
|
||||
public static GsonInternalAccess INSTANCE;
|
||||
|
||||
/**
|
||||
* Returns a type adapter for {@code} type that isn't {@code skipPast}. This
|
||||
* can be used for type adapters to compose other, simpler type adapters.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public abstract <T> TypeAdapter<T> getNextAdapter(
|
||||
Gson gson, TypeAdapterFactory skipPast, TypeToken<T> type);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.JsonReaderInternalAccess;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Internal-only APIs of JsonReader available only to other classes in Gson.
|
||||
*/
|
||||
public abstract class JsonReaderInternalAccess {
|
||||
public static JsonReaderInternalAccess INSTANCE;
|
||||
|
||||
/**
|
||||
* Changes the type of the current property name token to a string value.
|
||||
*/
|
||||
public abstract void promoteNameToValue(JsonReader reader) throws IOException;
|
||||
}
|
@ -16,6 +16,8 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Pair;
|
||||
|
||||
/**
|
||||
* A simple object that holds onto a pair of object references, first and second.
|
||||
*
|
||||
|
@ -1,247 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A map that provides ability to associate handlers for a specific type or all
|
||||
* of its sub-types
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*
|
||||
* @param <T> The handler that will be looked up by type
|
||||
*/
|
||||
public final class ParameterizedTypeHandlerMap<T> {
|
||||
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ParameterizedTypeHandlerMap.class.getName());
|
||||
/**
|
||||
* Map that is meant for storing default type adapters
|
||||
*/
|
||||
private final Map<Type, T> systemMap = new HashMap<Type, T>();
|
||||
private final Map<Type, T> userMap = new HashMap<Type, T>();
|
||||
/**
|
||||
* List of default type hierarchy adapters
|
||||
*/
|
||||
private final List<Pair<Class<?>, T>> systemTypeHierarchyList = new ArrayList<Pair<Class<?>, T>>();
|
||||
private final List<Pair<Class<?>, T>> userTypeHierarchyList = new ArrayList<Pair<Class<?>, T>>();
|
||||
private boolean modifiable = true;
|
||||
|
||||
public synchronized void registerForTypeHierarchy(Class<?> typeOfT, T value, boolean isSystem) {
|
||||
Pair<Class<?>, T> pair = new Pair<Class<?>, T>(typeOfT, value);
|
||||
registerForTypeHierarchy(pair, isSystem);
|
||||
}
|
||||
|
||||
public synchronized void registerForTypeHierarchy(Pair<Class<?>, T> pair, boolean isSystem) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
List<Pair<Class<?>, T>> typeHierarchyList = isSystem ? systemTypeHierarchyList : userTypeHierarchyList;
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(pair.first, typeHierarchyList);
|
||||
if (index >= 0) {
|
||||
logger.log(Level.WARNING, "Overriding the existing type handler for {0}", pair.first);
|
||||
typeHierarchyList.remove(index);
|
||||
}
|
||||
index = getIndexOfAnOverriddenHandler(pair.first, typeHierarchyList);
|
||||
if (index >= 0) {
|
||||
throw new IllegalArgumentException("The specified type handler for type " + pair.first
|
||||
+ " hides the previously registered type hierarchy handler for "
|
||||
+ typeHierarchyList.get(index).first + ". Gson does not allow this.");
|
||||
}
|
||||
// We want stack behavior for adding to this list. A type adapter added subsequently should
|
||||
// override a previously registered one.
|
||||
typeHierarchyList.add(0, pair);
|
||||
}
|
||||
|
||||
private static <T> int getIndexOfAnOverriddenHandler(Class<?> type, List<Pair<Class<?>, T>> typeHierarchyList) {
|
||||
for (int i = typeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = typeHierarchyList.get(i);
|
||||
if (type.isAssignableFrom(entry.first)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized void register(Type typeOfT, T value, boolean isSystem) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
if (hasSpecificHandlerFor(typeOfT)) {
|
||||
logger.log(Level.WARNING, "Overriding the existing type handler for {0}", typeOfT);
|
||||
}
|
||||
Map<Type, T> map = isSystem ? systemMap : userMap;
|
||||
map.put(typeOfT, value);
|
||||
}
|
||||
|
||||
public synchronized void registerIfAbsent(ParameterizedTypeHandlerMap<T> other) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
}
|
||||
for (Map.Entry<Type, T> entry : other.userMap.entrySet()) {
|
||||
if (!userMap.containsKey(entry.getKey())) {
|
||||
register(entry.getKey(), entry.getValue(), false);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Type, T> entry : other.systemMap.entrySet()) {
|
||||
if (!systemMap.containsKey(entry.getKey())) {
|
||||
register(entry.getKey(), entry.getValue(), true);
|
||||
}
|
||||
}
|
||||
// Quite important to traverse the typeHierarchyList from stack bottom first since
|
||||
// we want to register the handlers in the same order to preserve priority order
|
||||
for (int i = other.userTypeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = other.userTypeHierarchyList.get(i);
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first, userTypeHierarchyList);
|
||||
if (index < 0) {
|
||||
registerForTypeHierarchy(entry, false);
|
||||
}
|
||||
}
|
||||
for (int i = other.systemTypeHierarchyList.size()-1; i >= 0; --i) {
|
||||
Pair<Class<?>, T> entry = other.systemTypeHierarchyList.get(i);
|
||||
int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first, systemTypeHierarchyList);
|
||||
if (index < 0) {
|
||||
registerForTypeHierarchy(entry, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ParameterizedTypeHandlerMap<T> makeUnmodifiable() {
|
||||
modifiable = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized T getHandlerFor(Type type, boolean systemOnly) {
|
||||
T handler;
|
||||
if (!systemOnly) {
|
||||
handler = userMap.get(type);
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
handler = systemMap.get(type);
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
}
|
||||
Class<?> rawClass = $Gson$Types.getRawType(type);
|
||||
if (rawClass != type) {
|
||||
handler = getHandlerFor(rawClass, systemOnly);
|
||||
if (handler != null) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
// check if something registered for type hierarchy
|
||||
handler = getHandlerForTypeHierarchy(rawClass, systemOnly);
|
||||
return handler;
|
||||
}
|
||||
|
||||
private T getHandlerForTypeHierarchy(Class<?> type, boolean systemOnly) {
|
||||
if (!systemOnly) {
|
||||
for (Pair<Class<?>, T> entry : userTypeHierarchyList) {
|
||||
if (entry.first.isAssignableFrom(type)) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Pair<Class<?>, T> entry : systemTypeHierarchyList) {
|
||||
if (entry.first.isAssignableFrom(type)) {
|
||||
return entry.second;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized boolean hasSpecificHandlerFor(Type type) {
|
||||
return userMap.containsKey(type) || systemMap.containsKey(type);
|
||||
}
|
||||
|
||||
private static <T> int getIndexOfSpecificHandlerForTypeHierarchy(
|
||||
Class<?> type, List<Pair<Class<?>, T>> typeHierarchyList) {
|
||||
for (int i = typeHierarchyList.size()-1; i >= 0; --i) {
|
||||
if (type.equals(typeHierarchyList.get(i).first)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized ParameterizedTypeHandlerMap<T> copyOf() {
|
||||
ParameterizedTypeHandlerMap<T> copy = new ParameterizedTypeHandlerMap<T>();
|
||||
// Instead of individually registering entries in the map, make an efficient copy
|
||||
// of the list and map
|
||||
|
||||
// TODO (inder): Performance optimization. We can probably just share the
|
||||
// systemMap and systemTypeHierarchyList instead of making copies
|
||||
copy.systemMap.putAll(systemMap);
|
||||
copy.userMap.putAll(userMap);
|
||||
copy.systemTypeHierarchyList.addAll(systemTypeHierarchyList);
|
||||
copy.userTypeHierarchyList.addAll(userTypeHierarchyList);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{userTypeHierarchyList:{");
|
||||
appendList(sb, userTypeHierarchyList);
|
||||
sb.append("},systemTypeHierarchyList:{");
|
||||
appendList(sb, systemTypeHierarchyList);
|
||||
sb.append("},userMap:{");
|
||||
appendMap(sb, userMap);
|
||||
sb.append("},systemMap:{");
|
||||
appendMap(sb, systemMap);
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendList(StringBuilder sb, List<Pair<Class<?>,T>> list) {
|
||||
boolean first = true;
|
||||
for (Pair<Class<?>, T> entry : list) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(typeToString(entry.first)).append(':');
|
||||
sb.append(entry.second);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendMap(StringBuilder sb, Map<Type, T> map) {
|
||||
boolean first = true;
|
||||
for (Map.Entry<Type, T> entry : map.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(typeToString(entry.getKey())).append(':');
|
||||
sb.append(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private String typeToString(Type type) {
|
||||
return $Gson$Types.getRawType(type).getSimpleName();
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ import java.io.ObjectStreamClass;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.UnsafeAllocator;
|
||||
|
||||
/**
|
||||
* Do sneaky things to allocate objects without invoking their constructors.
|
||||
*
|
||||
|
@ -23,6 +23,11 @@ import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ArrayTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapterRuntimeTypeWrapper;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
@ -33,45 +38,43 @@ import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
* Adapt an array of objects.
|
||||
*/
|
||||
public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
if (!(type instanceof GenericArrayType || type instanceof Class && ((Class<?>) type).isArray())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type componentType = $Gson$Types.getArrayComponentType(type);
|
||||
TypeAdapter<?> componentTypeAdapter = context.getAdapter(TypeToken.get(componentType));
|
||||
// create() doesn't define a type parameter
|
||||
TypeAdapter<T> result = new ArrayTypeAdapter(
|
||||
context, componentTypeAdapter, $Gson$Types.getRawType(componentType));
|
||||
return result;
|
||||
TypeAdapter<?> componentTypeAdapter = gson.getAdapter(TypeToken.get(componentType));
|
||||
return new ArrayTypeAdapter(
|
||||
gson, componentTypeAdapter, $Gson$Types.getRawType(componentType));
|
||||
}
|
||||
};
|
||||
|
||||
private final Class<E> componentType;
|
||||
private final TypeAdapter<E> componentTypeAdapter;
|
||||
|
||||
public ArrayTypeAdapter(MiniGson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) {
|
||||
public ArrayTypeAdapter(Gson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) {
|
||||
this.componentTypeAdapter =
|
||||
new TypeAdapterRuntimeTypeWrapper<E>(context, componentTypeAdapter, componentType);
|
||||
this.componentType = componentType;
|
||||
}
|
||||
|
||||
public Object read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Object read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
List<E> list = new ArrayList<E>();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
E instance = componentTypeAdapter.read(reader);
|
||||
in.beginArray();
|
||||
while (in.hasNext()) {
|
||||
E instance = componentTypeAdapter.read(in);
|
||||
list.add(instance);
|
||||
}
|
||||
reader.endArray();
|
||||
in.endArray();
|
||||
Object array = Array.newInstance(componentType, list.size());
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Array.set(array, i, list.get(i));
|
||||
@ -80,17 +83,17 @@ public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override public void write(JsonWriter writer, Object array) throws IOException {
|
||||
@Override public void write(JsonWriter out, Object array) throws IOException {
|
||||
if (array == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginArray();
|
||||
out.beginArray();
|
||||
for (int i = 0, length = Array.getLength(array); i < length; i++) {
|
||||
final E value = (E) Array.get(array, i);
|
||||
componentTypeAdapter.write(writer, value);
|
||||
E value = (E) Array.get(array, i);
|
||||
componentTypeAdapter.write(out, value);
|
||||
}
|
||||
writer.endArray();
|
||||
out.endArray();
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
@ -32,20 +33,20 @@ import java.math.BigDecimal;
|
||||
public final class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal> {
|
||||
|
||||
@Override
|
||||
public BigDecimal read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public BigDecimal read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(reader.nextString());
|
||||
return new BigDecimal(in.nextString());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, BigDecimal value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, BigDecimal value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
@ -32,20 +33,20 @@ import java.math.BigInteger;
|
||||
public final class BigIntegerTypeAdapter extends TypeAdapter<BigInteger> {
|
||||
|
||||
@Override
|
||||
public BigInteger read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public BigInteger read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigInteger(reader.nextString());
|
||||
return new BigInteger(in.nextString());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, BigInteger value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, BigInteger value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapterRuntimeTypeWrapper;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ObjectConstructor;
|
||||
@ -31,14 +35,14 @@ import java.util.Collection;
|
||||
/**
|
||||
* Adapt a homogeneous collection of objects.
|
||||
*/
|
||||
public final class CollectionTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
public final class CollectionTypeAdapterFactory implements TypeAdapterFactory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
@ -47,11 +51,11 @@ public final class CollectionTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
}
|
||||
|
||||
Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
|
||||
TypeAdapter<?> elementTypeAdapter = context.getAdapter(TypeToken.get(elementType));
|
||||
TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter
|
||||
TypeAdapter<T> result = new Adapter(context, elementType, elementTypeAdapter, constructor);
|
||||
TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -59,7 +63,7 @@ public final class CollectionTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final TypeAdapter<E> elementTypeAdapter;
|
||||
private final ObjectConstructor<? extends Collection<E>> constructor;
|
||||
|
||||
public Adapter(MiniGson context, Type elementType,
|
||||
public Adapter(Gson context, Type elementType,
|
||||
TypeAdapter<E> elementTypeAdapter,
|
||||
ObjectConstructor<? extends Collection<E>> constructor) {
|
||||
this.elementTypeAdapter =
|
||||
@ -67,33 +71,33 @@ public final class CollectionTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Collection<E> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Collection<E> read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<E> collection = constructor.construct();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
E instance = elementTypeAdapter.read(reader);
|
||||
in.beginArray();
|
||||
while (in.hasNext()) {
|
||||
E instance = elementTypeAdapter.read(in);
|
||||
collection.add(instance);
|
||||
}
|
||||
reader.endArray();
|
||||
in.endArray();
|
||||
return collection;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Collection<E> collection) throws IOException {
|
||||
public void write(JsonWriter out, Collection<E> collection) throws IOException {
|
||||
if (collection == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginArray();
|
||||
out.beginArray();
|
||||
for (E element : collection) {
|
||||
elementTypeAdapter.write(writer, element);
|
||||
elementTypeAdapter.write(out, element);
|
||||
}
|
||||
writer.endArray();
|
||||
out.endArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,11 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.DateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
@ -37,9 +41,9 @@ import java.util.TimeZone;
|
||||
* to synchronize its read and write methods.
|
||||
*/
|
||||
public final class DateTypeAdapter extends TypeAdapter<Date> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) new DateTypeAdapter() : null;
|
||||
}
|
||||
};
|
||||
@ -56,12 +60,12 @@ public final class DateTypeAdapter extends TypeAdapter<Date> {
|
||||
return iso8601Format;
|
||||
}
|
||||
|
||||
@Override public Date read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
@Override public Date read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return deserializeToDate(reader.nextString());
|
||||
return deserializeToDate(in.nextString());
|
||||
}
|
||||
|
||||
private synchronized Date deserializeToDate(String json) {
|
||||
@ -80,12 +84,12 @@ public final class DateTypeAdapter extends TypeAdapter<Date> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void write(JsonWriter writer, Date value) throws IOException {
|
||||
@Override public synchronized void write(JsonWriter out, Date value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
String dateFormatAsString = enUsFormat.format(value);
|
||||
writer.value(dateFormatAsString);
|
||||
out.value(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.ExclusionStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This type adapter skips values using an exclusion strategy. It may delegate
|
||||
* to another type adapter if only one direction is excluded.
|
||||
*/
|
||||
public final class ExcludedTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ExclusionStrategy serializationExclusionStrategy;
|
||||
private final ExclusionStrategy deserializationExclusionStrategy;
|
||||
|
||||
public ExcludedTypeAdapterFactory(ExclusionStrategy serializationExclusionStrategy,
|
||||
ExclusionStrategy deserializationExclusionStrategy) {
|
||||
this.serializationExclusionStrategy = serializationExclusionStrategy;
|
||||
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final MiniGson context, final TypeToken<T> type) {
|
||||
Class<?> rawType = type.getRawType();
|
||||
final boolean skipSerialize = serializationExclusionStrategy.shouldSkipClass(rawType);
|
||||
final boolean skipDeserialize = deserializationExclusionStrategy.shouldSkipClass(rawType);
|
||||
|
||||
if (!skipSerialize && !skipDeserialize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
/**
|
||||
* The delegate is lazily created because it may not be needed, and
|
||||
* creating it may fail.
|
||||
*/
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (skipDeserialize) {
|
||||
reader.skipValue();
|
||||
return null;
|
||||
}
|
||||
return delegate().read(reader);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (skipSerialize) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
delegate().write(writer, value);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = context.getNextAdapter(ExcludedTypeAdapterFactory.this, type));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ import java.util.Map;
|
||||
*
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public final class JsonElementReader extends JsonReader {
|
||||
public final class JsonTreeReader extends JsonReader {
|
||||
private static final Reader UNREADABLE_READER = new Reader() {
|
||||
@Override public int read(char[] buffer, int offset, int count) throws IOException {
|
||||
throw new AssertionError();
|
||||
@ -50,7 +50,7 @@ public final class JsonElementReader extends JsonReader {
|
||||
|
||||
private final List<Object> stack = new ArrayList<Object>();
|
||||
|
||||
public JsonElementReader(JsonElement element) {
|
||||
public JsonTreeReader(JsonElement element) {
|
||||
super(UNREADABLE_READER);
|
||||
stack.add(element);
|
||||
}
|
||||
@ -216,4 +216,12 @@ public final class JsonElementReader extends JsonReader {
|
||||
@Override public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public void promoteNameToValue() throws IOException {
|
||||
expect(JsonToken.NAME);
|
||||
Iterator<?> i = (Iterator<?>) peekStack();
|
||||
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();
|
||||
stack.add(entry.getValue());
|
||||
stack.add(new JsonPrimitive((String)entry.getKey()));
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ import java.util.List;
|
||||
/**
|
||||
* This writer creates a JsonElement.
|
||||
*/
|
||||
public final class JsonElementWriter extends JsonWriter {
|
||||
public final class JsonTreeWriter extends JsonWriter {
|
||||
private static final Writer UNWRITABLE_WRITER = new Writer() {
|
||||
@Override public void write(char[] buffer, int offset, int counter) {
|
||||
throw new AssertionError();
|
||||
@ -55,7 +55,7 @@ public final class JsonElementWriter extends JsonWriter {
|
||||
/** the JSON element constructed by this writer. */
|
||||
private JsonElement product = JsonNull.INSTANCE; // TODO: is this really what we want?;
|
||||
|
||||
public JsonElementWriter() {
|
||||
public JsonTreeWriter() {
|
||||
super(UNWRITABLE_WRITER);
|
||||
}
|
||||
|
@ -16,11 +16,19 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonTreeWriter;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapterRuntimeTypeWrapper;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapters;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.JsonReaderInternalAccess;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ObjectConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Streams;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
@ -57,9 +65,9 @@ import java.util.Map;
|
||||
* But GSON is unable to deserialize this value because the JSON string name is
|
||||
* just the {@link Object#toString() toString()} of the map key. Attempting to
|
||||
* convert the above JSON to an object fails with a parse exception:
|
||||
* <pre>com.google.gson.JsonParseException: Expecting object found: "(5,6)"
|
||||
* at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
|
||||
* at com.google.gson.ObjectNavigator.navigateClassFields
|
||||
* <pre>com.massivecraft.mcore2.lib.gson.JsonParseException: Expecting object found: "(5,6)"
|
||||
* at com.massivecraft.mcore2.lib.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
|
||||
* at com.massivecraft.mcore2.lib.gson.ObjectNavigator.navigateClassFields
|
||||
* ...</pre>
|
||||
*
|
||||
* <h3>Maps as JSON arrays</h3>
|
||||
@ -99,7 +107,7 @@ import java.util.Map;
|
||||
* This format will serialize and deserialize just fine as long as this adapter
|
||||
* is registered.
|
||||
*/
|
||||
public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
public final class MapTypeAdapterFactory implements TypeAdapterFactory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
private final boolean complexMapKeySerialization;
|
||||
|
||||
@ -109,7 +117,7 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
this.complexMapKeySerialization = complexMapKeySerialization;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
@ -119,13 +127,13 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
|
||||
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);
|
||||
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc);
|
||||
TypeAdapter<?> keyAdapter = getKeyAdapter(context, keyAndValueTypes[0]);
|
||||
TypeAdapter<?> valueAdapter = context.getAdapter(TypeToken.get(keyAndValueTypes[1]));
|
||||
TypeAdapter<?> keyAdapter = getKeyAdapter(gson, keyAndValueTypes[0]);
|
||||
TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(keyAndValueTypes[1]));
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
// we don't define a type parameter for the key or value types
|
||||
TypeAdapter<T> result = new Adapter(context, keyAndValueTypes[0], keyAdapter,
|
||||
TypeAdapter<T> result = new Adapter(gson, keyAndValueTypes[0], keyAdapter,
|
||||
keyAndValueTypes[1], valueAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
@ -133,7 +141,7 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
/**
|
||||
* Returns a type adapter that writes the value as a string.
|
||||
*/
|
||||
private TypeAdapter<?> getKeyAdapter(MiniGson context, Type keyType) {
|
||||
private TypeAdapter<?> getKeyAdapter(Gson context, Type keyType) {
|
||||
return (keyType == boolean.class || keyType == Boolean.class)
|
||||
? TypeAdapters.BOOLEAN_AS_STRING
|
||||
: context.getAdapter(TypeToken.get(keyType));
|
||||
@ -144,7 +152,7 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final TypeAdapter<V> valueTypeAdapter;
|
||||
private final ObjectConstructor<? extends Map<K, V>> constructor;
|
||||
|
||||
public Adapter(MiniGson context, Type keyType, TypeAdapter<K> keyTypeAdapter,
|
||||
public Adapter(Gson context, Type keyType, TypeAdapter<K> keyTypeAdapter,
|
||||
Type valueType, TypeAdapter<V> valueTypeAdapter,
|
||||
ObjectConstructor<? extends Map<K, V>> constructor) {
|
||||
this.keyTypeAdapter =
|
||||
@ -154,57 +162,57 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Map<K, V> read(JsonReader reader) throws IOException {
|
||||
JsonToken peek = reader.peek();
|
||||
public Map<K, V> read(JsonReader in) throws IOException {
|
||||
JsonToken peek = in.peek();
|
||||
if (peek == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<K, V> map = constructor.construct();
|
||||
|
||||
if (peek == JsonToken.BEGIN_ARRAY) {
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
reader.beginArray(); // entry array
|
||||
K key = keyTypeAdapter.read(reader);
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
in.beginArray();
|
||||
while (in.hasNext()) {
|
||||
in.beginArray(); // entry array
|
||||
K key = keyTypeAdapter.read(in);
|
||||
V value = valueTypeAdapter.read(in);
|
||||
V replaced = map.put(key, value);
|
||||
if (replaced != null) {
|
||||
throw new JsonSyntaxException("duplicate key: " + key);
|
||||
}
|
||||
reader.endArray();
|
||||
in.endArray();
|
||||
}
|
||||
reader.endArray();
|
||||
in.endArray();
|
||||
} else {
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String keyString = reader.nextName();
|
||||
K key = keyTypeAdapter.fromJsonElement(new JsonPrimitive(keyString));
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);
|
||||
K key = keyTypeAdapter.read(in);
|
||||
V value = valueTypeAdapter.read(in);
|
||||
V replaced = map.put(key, value);
|
||||
if (replaced != null) {
|
||||
throw new JsonSyntaxException("duplicate key: " + key);
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
in.endObject();
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Map<K, V> map) throws IOException {
|
||||
public void write(JsonWriter out, Map<K, V> map) throws IOException {
|
||||
if (map == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!complexMapKeySerialization) {
|
||||
writer.beginObject();
|
||||
out.beginObject();
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
writer.name(String.valueOf(entry.getKey()));
|
||||
valueTypeAdapter.write(writer, entry.getValue());
|
||||
out.name(String.valueOf(entry.getKey()));
|
||||
valueTypeAdapter.write(out, entry.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
out.endObject();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -213,29 +221,29 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
|
||||
List<V> values = new ArrayList<V>(map.size());
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
JsonElement keyElement = keyTypeAdapter.toJsonElement(entry.getKey());
|
||||
JsonElement keyElement = toJsonTree(keyTypeAdapter, entry.getKey());
|
||||
keys.add(keyElement);
|
||||
values.add(entry.getValue());
|
||||
hasComplexKeys |= keyElement.isJsonArray() || keyElement.isJsonObject();
|
||||
}
|
||||
|
||||
if (hasComplexKeys) {
|
||||
writer.beginArray();
|
||||
out.beginArray();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
writer.beginArray(); // entry array
|
||||
Streams.write(keys.get(i), writer);
|
||||
valueTypeAdapter.write(writer, values.get(i));
|
||||
writer.endArray();
|
||||
out.beginArray(); // entry array
|
||||
Streams.write(keys.get(i), out);
|
||||
valueTypeAdapter.write(out, values.get(i));
|
||||
out.endArray();
|
||||
}
|
||||
writer.endArray();
|
||||
out.endArray();
|
||||
} else {
|
||||
writer.beginObject();
|
||||
out.beginObject();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
JsonElement keyElement = keys.get(i);
|
||||
writer.name(keyToString(keyElement));
|
||||
valueTypeAdapter.write(writer, values.get(i));
|
||||
out.name(keyToString(keyElement));
|
||||
valueTypeAdapter.write(out, values.get(i));
|
||||
}
|
||||
writer.endObject();
|
||||
out.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,4 +266,16 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this when TypeAdapter.toJsonTree() is public
|
||||
private static <T> JsonElement toJsonTree(TypeAdapter<T> typeAdapter, T value) {
|
||||
try {
|
||||
JsonTreeWriter jsonWriter = new JsonTreeWriter();
|
||||
jsonWriter.setLenient(true);
|
||||
typeAdapter.write(jsonWriter, value);
|
||||
return jsonWriter.get();
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A basic binding between JSON and Java objects.
|
||||
*/
|
||||
public final class MiniGson {
|
||||
/**
|
||||
* This thread local guards against reentrant calls to getAdapter(). In
|
||||
* certain object graphs, creating an adapter for a type may recursively
|
||||
* require an adapter for the same type! Without intervention, the recursive
|
||||
* lookup would stack overflow. We cheat by returning a proxy type adapter.
|
||||
* The proxy is wired up once the initial adapter has been created.
|
||||
*/
|
||||
private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls
|
||||
= new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>() {
|
||||
@Override protected Map<TypeToken<?>, FutureTypeAdapter<?>> initialValue() {
|
||||
return new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
|
||||
}
|
||||
};
|
||||
|
||||
private final List<TypeAdapter.Factory> factories;
|
||||
|
||||
private MiniGson(Builder builder) {
|
||||
ConstructorConstructor constructorConstructor = new ConstructorConstructor();
|
||||
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||
if (builder.addDefaultFactories) {
|
||||
factories.add(TypeAdapters.BOOLEAN_FACTORY);
|
||||
factories.add(TypeAdapters.INTEGER_FACTORY);
|
||||
factories.add(TypeAdapters.DOUBLE_FACTORY);
|
||||
factories.add(TypeAdapters.FLOAT_FACTORY);
|
||||
factories.add(TypeAdapters.LONG_FACTORY);
|
||||
factories.add(TypeAdapters.STRING_FACTORY);
|
||||
}
|
||||
factories.addAll(builder.factories);
|
||||
if (builder.addDefaultFactories) {
|
||||
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
|
||||
factories.add(new StringToValueMapTypeAdapterFactory(constructorConstructor));
|
||||
factories.add(ArrayTypeAdapter.FACTORY);
|
||||
factories.add(ObjectTypeAdapter.FACTORY);
|
||||
factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor));
|
||||
}
|
||||
this.factories = Collections.unmodifiableList(factories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type adapter for {@code} type.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
|
||||
// TODO: create a cache!
|
||||
|
||||
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
|
||||
@SuppressWarnings("unchecked") // the key and value type parameters always agree
|
||||
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
|
||||
if (ongoingCall != null) {
|
||||
return ongoingCall;
|
||||
}
|
||||
|
||||
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
|
||||
threadCalls.put(type, call);
|
||||
try {
|
||||
for (TypeAdapter.Factory factory : factories) {
|
||||
TypeAdapter<T> candidate = factory.create(this, type);
|
||||
if (candidate != null) {
|
||||
call.setDelegate(candidate);
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("This MiniGSON cannot handle " + type);
|
||||
} finally {
|
||||
threadCalls.remove(type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type adapter for {@code} type that isn't {@code skipPast}. This
|
||||
* can be used for type adapters to compose other, simpler type adapters.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public <T> TypeAdapter<T> getNextAdapter(TypeAdapter.Factory skipPast, TypeToken<T> type) {
|
||||
boolean skipPastFound = false;
|
||||
|
||||
for (TypeAdapter.Factory factory : factories) {
|
||||
if (!skipPastFound) {
|
||||
if (factory == skipPast) {
|
||||
skipPastFound = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeAdapter<T> candidate = factory.create(this, type);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("This MiniGSON cannot serialize " + type);
|
||||
}
|
||||
|
||||
static class FutureTypeAdapter<T> extends TypeAdapter<T> {
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
public void setDelegate(TypeAdapter<T> typeAdapter) {
|
||||
if (delegate != null) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
delegate = typeAdapter;
|
||||
}
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (delegate == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return delegate.read(reader);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (delegate == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
delegate.write(writer, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type adapter for {@code} type.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public <T> TypeAdapter<T> getAdapter(Class<T> type) {
|
||||
return getAdapter(TypeToken.get(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type adapters of this context in order of precedence.
|
||||
*/
|
||||
public List<TypeAdapter.Factory> getFactories() {
|
||||
return factories;
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private final List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||
boolean addDefaultFactories = true;
|
||||
|
||||
public Builder factory(TypeAdapter.Factory factory) {
|
||||
factories.add(factory);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withoutDefaultFactories() {
|
||||
this.addDefaultFactories = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder typeAdapter(final Class<T> type, final TypeAdapter<T> typeAdapter) {
|
||||
factories.add(TypeAdapters.newFactory(type, typeAdapter));
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder typeAdapter(TypeToken<T> type, TypeAdapter<T> typeAdapter) {
|
||||
factories.add(TypeAdapters.newFactory(type, typeAdapter));
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder typeHierarchyAdapter(Class<T> type, TypeAdapter<T> typeAdapter) {
|
||||
factories.add(TypeAdapters.newTypeHierarchyFactory(type, typeAdapter));
|
||||
return this;
|
||||
}
|
||||
|
||||
public MiniGson build() {
|
||||
return new MiniGson(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ObjectTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
@ -32,54 +36,54 @@ import java.util.Map;
|
||||
* serialization and a primitive/Map/List on deserialization.
|
||||
*/
|
||||
public final class ObjectTypeAdapter extends TypeAdapter<Object> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
if (type.getRawType() == Object.class) {
|
||||
return (TypeAdapter<T>) new ObjectTypeAdapter(context);
|
||||
return (TypeAdapter<T>) new ObjectTypeAdapter(gson);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private final MiniGson miniGson;
|
||||
private final Gson gson;
|
||||
|
||||
private ObjectTypeAdapter(MiniGson miniGson) {
|
||||
this.miniGson = miniGson;
|
||||
private ObjectTypeAdapter(Gson gson) {
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
@Override public Object read(JsonReader reader) throws IOException {
|
||||
JsonToken token = reader.peek();
|
||||
@Override public Object read(JsonReader in) throws IOException {
|
||||
JsonToken token = in.peek();
|
||||
switch (token) {
|
||||
case BEGIN_ARRAY:
|
||||
List<Object> list = new ArrayList<Object>();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
list.add(read(reader));
|
||||
in.beginArray();
|
||||
while (in.hasNext()) {
|
||||
list.add(read(in));
|
||||
}
|
||||
reader.endArray();
|
||||
in.endArray();
|
||||
return list;
|
||||
|
||||
case BEGIN_OBJECT:
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
map.put(reader.nextName(), read(reader));
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
map.put(in.nextName(), read(in));
|
||||
}
|
||||
reader.endObject();
|
||||
in.endObject();
|
||||
return map;
|
||||
|
||||
case STRING:
|
||||
return reader.nextString();
|
||||
return in.nextString();
|
||||
|
||||
case NUMBER:
|
||||
return reader.nextDouble();
|
||||
return in.nextDouble();
|
||||
|
||||
case BOOLEAN:
|
||||
return reader.nextBoolean();
|
||||
return in.nextBoolean();
|
||||
|
||||
case NULL:
|
||||
reader.nextNull();
|
||||
in.nextNull();
|
||||
return null;
|
||||
|
||||
}
|
||||
@ -87,19 +91,19 @@ public final class ObjectTypeAdapter extends TypeAdapter<Object> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override public void write(JsonWriter writer, Object value) throws IOException {
|
||||
@Override public void write(JsonWriter out, Object value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) miniGson.getAdapter(value.getClass());
|
||||
TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass());
|
||||
if (typeAdapter instanceof ObjectTypeAdapter) {
|
||||
writer.beginObject();
|
||||
writer.endObject();
|
||||
out.beginObject();
|
||||
out.endObject();
|
||||
return;
|
||||
}
|
||||
|
||||
typeAdapter.write(writer, value);
|
||||
typeAdapter.write(out, value);
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
||||
final class Reflection {
|
||||
/**
|
||||
* Finds a compatible runtime type if it is more specific
|
||||
*/
|
||||
public static Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
|
||||
if (value != null
|
||||
&& (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {
|
||||
type = value.getClass();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
@ -16,9 +16,17 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ReflectiveTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TypeAdapterRuntimeTypeWrapper;
|
||||
import com.massivecraft.mcore2.lib.gson.FieldNamingStrategy;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.SerializedName;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Excluder;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ObjectConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.Primitives;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
@ -27,7 +35,6 @@ import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -36,26 +43,28 @@ import java.util.Map;
|
||||
/**
|
||||
* Type adapter that reflects over the fields and methods of a class.
|
||||
*/
|
||||
public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
private final FieldNamingStrategy fieldNamingPolicy;
|
||||
private final Excluder excluder;
|
||||
|
||||
public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor,
|
||||
FieldNamingStrategy fieldNamingPolicy, Excluder excluder) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.excluder = excluder;
|
||||
}
|
||||
|
||||
protected boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !f.isSynthetic();
|
||||
public boolean excludeField(Field f, boolean serialize) {
|
||||
return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize);
|
||||
}
|
||||
|
||||
protected boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !f.isSynthetic();
|
||||
private String getFieldName(Field f) {
|
||||
SerializedName serializedName = f.getAnnotation(SerializedName.class);
|
||||
return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value();
|
||||
}
|
||||
|
||||
protected String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return f.getName();
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, final TypeToken<T> type) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
|
||||
Class<? super T> raw = type.getRawType();
|
||||
|
||||
if (!Object.class.isAssignableFrom(raw)) {
|
||||
@ -63,11 +72,11 @@ public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
}
|
||||
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(type);
|
||||
return new Adapter<T>(constructor, getBoundFields(context, type, raw));
|
||||
return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
|
||||
}
|
||||
|
||||
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
|
||||
final MiniGson context, final Field field, final String name,
|
||||
final Gson context, final Field field, final String name,
|
||||
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
|
||||
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
|
||||
|
||||
@ -92,8 +101,7 @@ public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
};
|
||||
}
|
||||
|
||||
private Map<String, BoundField> getBoundFields(
|
||||
MiniGson context, TypeToken<?> type, Class<?> raw) {
|
||||
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
|
||||
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
|
||||
if (raw.isInterface()) {
|
||||
return result;
|
||||
@ -102,15 +110,15 @@ public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
Type declaredType = type.getType();
|
||||
while (raw != Object.class) {
|
||||
Field[] fields = raw.getDeclaredFields();
|
||||
AccessibleObject.setAccessible(fields, true);
|
||||
for (Field field : fields) {
|
||||
boolean serialize = serializeField(raw, field, declaredType);
|
||||
boolean deserialize = deserializeField(raw, field, declaredType);
|
||||
boolean serialize = excludeField(field, true);
|
||||
boolean deserialize = excludeField(field, false);
|
||||
if (!serialize && !deserialize) {
|
||||
continue;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
|
||||
BoundField boundField = createBoundField(context, field, getFieldName(raw, field, declaredType),
|
||||
BoundField boundField = createBoundField(context, field, getFieldName(field),
|
||||
TypeToken.get(fieldType), serialize, deserialize);
|
||||
BoundField previous = result.put(boundField.name, boundField);
|
||||
if (previous != null) {
|
||||
@ -149,9 +157,9 @@ public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public T read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -160,15 +168,15 @@ public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
// TODO: null out the other fields?
|
||||
|
||||
try {
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String name = reader.nextName();
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
String name = in.nextName();
|
||||
BoundField field = boundFields.get(name);
|
||||
if (field == null || !field.deserialized) {
|
||||
// TODO: define a better policy
|
||||
reader.skipValue();
|
||||
in.skipValue();
|
||||
} else {
|
||||
field.read(reader, instance);
|
||||
field.read(in, instance);
|
||||
}
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
@ -176,29 +184,29 @@ public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
reader.endObject();
|
||||
in.endObject();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, T value) throws IOException {
|
||||
public void write(JsonWriter out, T value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
out.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
out.beginObject();
|
||||
try {
|
||||
for (BoundField boundField : boundFields.values()) {
|
||||
if (boundField.serialized) {
|
||||
writer.name(boundField.name);
|
||||
boundField.write(writer, value);
|
||||
out.name(boundField.name);
|
||||
boundField.write(out, value);
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
writer.endObject();
|
||||
out.endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,11 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.SqlDateTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
@ -34,9 +38,9 @@ import java.text.SimpleDateFormat;
|
||||
* to synchronize its read and write methods.
|
||||
*/
|
||||
public final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
return typeToken.getRawType() == java.sql.Date.class
|
||||
? (TypeAdapter<T>) new SqlDateTypeAdapter() : null;
|
||||
}
|
||||
@ -45,13 +49,13 @@ public final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
|
||||
private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");
|
||||
|
||||
@Override
|
||||
public synchronized java.sql.Date read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public synchronized java.sql.Date read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final long utilDate = format.parse(reader.nextString()).getTime();
|
||||
final long utilDate = format.parse(in.nextString()).getTime();
|
||||
return new java.sql.Date(utilDate);
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
@ -59,7 +63,7 @@ public final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(JsonWriter writer, java.sql.Date value) throws IOException {
|
||||
writer.value(value == null ? null : format.format(value));
|
||||
public synchronized void write(JsonWriter out, java.sql.Date value) throws IOException {
|
||||
out.value(value == null ? null : format.format(value));
|
||||
}
|
||||
}
|
||||
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ConstructorConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.ObjectConstructor;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapt a map whose keys are strings.
|
||||
*/
|
||||
public final class StringToValueMapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
public StringToValueMapTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
if (!(type instanceof ParameterizedType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Map.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawType);
|
||||
if (keyAndValueTypes[0] != String.class) {
|
||||
return null;
|
||||
}
|
||||
TypeAdapter<?> valueAdapter = context.getAdapter(TypeToken.get(keyAndValueTypes[1]));
|
||||
|
||||
ObjectConstructor<?> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
// we don't define a type parameter for the key or value types
|
||||
TypeAdapter<T> result = new Adapter(valueAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final class Adapter<V> extends TypeAdapter<Map<String, V>> {
|
||||
private final TypeAdapter<V> valueTypeAdapter;
|
||||
private final ObjectConstructor<? extends Map<String, V>> constructor;
|
||||
|
||||
public Adapter(TypeAdapter<V> valueTypeAdapter,
|
||||
ObjectConstructor<? extends Map<String, V>> constructor) {
|
||||
this.valueTypeAdapter = valueTypeAdapter;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Map<String, V> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, V> map = constructor.construct();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String key = reader.nextName();
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
map.put(key, value);
|
||||
}
|
||||
reader.endObject();
|
||||
return map;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Map<String, V> map) throws IOException {
|
||||
if (map == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, V> entry : map.entrySet()) {
|
||||
writer.name(entry.getKey());
|
||||
valueTypeAdapter.write(writer, entry.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,11 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.TimeTypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
@ -36,29 +40,29 @@ import java.util.Date;
|
||||
* to synchronize its read and write methods.
|
||||
*/
|
||||
public final class TimeTypeAdapter extends TypeAdapter<Time> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new TimeTypeAdapter() : null;
|
||||
}
|
||||
};
|
||||
|
||||
private final DateFormat format = new SimpleDateFormat("hh:mm:ss a");
|
||||
|
||||
@Override public synchronized Time read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
@Override public synchronized Time read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Date date = format.parse(reader.nextString());
|
||||
Date date = format.parse(in.nextString());
|
||||
return new Time(date.getTime());
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void write(JsonWriter writer, Time value) throws IOException {
|
||||
writer.value(value == null ? null : format.format(value));
|
||||
@Override public synchronized void write(JsonWriter out, Time value) throws IOException {
|
||||
out.value(value == null ? null : format.format(value));
|
||||
}
|
||||
}
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
public abstract class TypeAdapter<T> {
|
||||
public abstract T read(JsonReader reader) throws IOException;
|
||||
public abstract void write(JsonWriter writer, T value) throws IOException;
|
||||
|
||||
public final String toJson(T value) throws IOException {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
write(stringWriter, value);
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
public final void write(Writer out, T value) throws IOException {
|
||||
JsonWriter writer = new JsonWriter(out);
|
||||
write(writer, value);
|
||||
}
|
||||
|
||||
public final T fromJson(String json) throws IOException {
|
||||
return read(new StringReader(json));
|
||||
}
|
||||
|
||||
public final T read(Reader in) throws IOException {
|
||||
JsonReader reader = new JsonReader(in);
|
||||
reader.setLenient(true);
|
||||
return read(reader);
|
||||
}
|
||||
|
||||
public JsonElement toJsonElement(T src) {
|
||||
try {
|
||||
JsonElementWriter jsonWriter = new JsonElementWriter();
|
||||
jsonWriter.setLenient(true);
|
||||
write(jsonWriter, src);
|
||||
return jsonWriter.get();
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public T fromJsonElement(JsonElement json) {
|
||||
try {
|
||||
JsonReader jsonReader = new JsonElementReader(json);
|
||||
jsonReader.setLenient(true);
|
||||
return read(jsonReader);
|
||||
} catch (IOException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public interface Factory {
|
||||
<T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type);
|
||||
}
|
||||
}
|
@ -15,33 +15,36 @@
|
||||
*/
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.ReflectiveTypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
||||
final class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
|
||||
|
||||
private final MiniGson context;
|
||||
private final Gson context;
|
||||
private final TypeAdapter<T> delegate;
|
||||
private final Type type;
|
||||
|
||||
TypeAdapterRuntimeTypeWrapper(MiniGson context, TypeAdapter<T> delegate, Type type) {
|
||||
TypeAdapterRuntimeTypeWrapper(Gson context, TypeAdapter<T> delegate, Type type) {
|
||||
this.context = context;
|
||||
this.delegate = delegate;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(JsonReader reader) throws IOException {
|
||||
return delegate.read(reader);
|
||||
public T read(JsonReader in) throws IOException {
|
||||
return delegate.read(in);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public void write(JsonWriter writer, T value) throws IOException {
|
||||
public void write(JsonWriter out, T value) throws IOException {
|
||||
// Order of preference for choosing type adapters
|
||||
// First preference: a type adapter registered for the runtime type
|
||||
// Second preference: a type adapter registered for the declared type
|
||||
@ -49,7 +52,7 @@ final class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
|
||||
// Fourth preference: reflective type adapter for the declared type
|
||||
|
||||
TypeAdapter chosen = delegate;
|
||||
Type runtimeType = Reflection.getRuntimeTypeIfMoreSpecific(type, value);
|
||||
Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);
|
||||
if (runtimeType != type) {
|
||||
TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));
|
||||
if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {
|
||||
@ -64,6 +67,17 @@ final class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
|
||||
chosen = runtimeTypeAdapter;
|
||||
}
|
||||
}
|
||||
chosen.write(writer, value);
|
||||
chosen.write(out, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a compatible runtime type if it is more specific
|
||||
*/
|
||||
private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
|
||||
if (value != null
|
||||
&& (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {
|
||||
type = value.getClass();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
@ -16,19 +16,6 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.internal.bind;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.LazilyParsedNumber;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URI;
|
||||
@ -39,39 +26,72 @@ import java.util.BitSet;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.Gson;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonArray;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonElement;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonIOException;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonNull;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonObject;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonPrimitive;
|
||||
import com.massivecraft.mcore2.lib.gson.JsonSyntaxException;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapter;
|
||||
import com.massivecraft.mcore2.lib.gson.TypeAdapterFactory;
|
||||
import com.massivecraft.mcore2.lib.gson.annotations.SerializedName;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.LazilyParsedNumber;
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Type adapters for basic types.
|
||||
*/
|
||||
public final class TypeAdapters {
|
||||
private TypeAdapters() {}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static final TypeAdapter<Class> CLASS = new TypeAdapter<Class>() {
|
||||
@Override
|
||||
public void write(JsonWriter out, Class value) throws IOException {
|
||||
throw new UnsupportedOperationException("Attempted to serialize java.lang.Class: "
|
||||
+ value.getName() + ". Forgot to register a type adapter?");
|
||||
}
|
||||
@Override
|
||||
public Class read(JsonReader in) throws IOException {
|
||||
throw new UnsupportedOperationException(
|
||||
"Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?");
|
||||
}
|
||||
};
|
||||
public static final TypeAdapterFactory CLASS_FACTORY = newFactory(Class.class, CLASS);
|
||||
|
||||
public static final TypeAdapter<BitSet> BIT_SET = new TypeAdapter<BitSet>() {
|
||||
public BitSet read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public BitSet read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
BitSet bitset = new BitSet();
|
||||
reader.beginArray();
|
||||
in.beginArray();
|
||||
int i = 0;
|
||||
JsonToken tokenType = reader.peek();
|
||||
JsonToken tokenType = in.peek();
|
||||
while (tokenType != JsonToken.END_ARRAY) {
|
||||
boolean set;
|
||||
switch (tokenType) {
|
||||
case NUMBER:
|
||||
set = reader.nextInt() != 0;
|
||||
set = in.nextInt() != 0;
|
||||
break;
|
||||
case BOOLEAN:
|
||||
set = reader.nextBoolean();
|
||||
set = in.nextBoolean();
|
||||
break;
|
||||
case STRING:
|
||||
String stringValue = reader.nextString();
|
||||
String stringValue = in.nextString();
|
||||
try {
|
||||
set = Integer.parseInt(stringValue) != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
@ -86,48 +106,48 @@ public final class TypeAdapters {
|
||||
bitset.set(i);
|
||||
}
|
||||
++i;
|
||||
tokenType = reader.peek();
|
||||
tokenType = in.peek();
|
||||
}
|
||||
reader.endArray();
|
||||
in.endArray();
|
||||
return bitset;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, BitSet src) throws IOException {
|
||||
public void write(JsonWriter out, BitSet src) throws IOException {
|
||||
if (src == null) {
|
||||
writer.nullValue();
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginArray();
|
||||
out.beginArray();
|
||||
for (int i = 0; i < src.length(); i++) {
|
||||
int value = (src.get(i)) ? 1 : 0;
|
||||
writer.value(value);
|
||||
out.value(value);
|
||||
}
|
||||
writer.endArray();
|
||||
out.endArray();
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory BIT_SET_FACTORY = newFactory(BitSet.class, BIT_SET);
|
||||
public static final TypeAdapterFactory BIT_SET_FACTORY = newFactory(BitSet.class, BIT_SET);
|
||||
|
||||
public static final TypeAdapter<Boolean> BOOLEAN = new TypeAdapter<Boolean>() {
|
||||
@Override
|
||||
public Boolean read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Boolean read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
} else if (reader.peek() == JsonToken.STRING) {
|
||||
} else if (in.peek() == JsonToken.STRING) {
|
||||
// support strings for compatibility with GSON 1.7
|
||||
return Boolean.parseBoolean(reader.nextString());
|
||||
return Boolean.parseBoolean(in.nextString());
|
||||
}
|
||||
return reader.nextBoolean();
|
||||
return in.nextBoolean();
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Boolean value) throws IOException {
|
||||
public void write(JsonWriter out, Boolean value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
writer.value(value);
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
@ -136,336 +156,332 @@ public final class TypeAdapters {
|
||||
* otherwise permitted.
|
||||
*/
|
||||
public static final TypeAdapter<Boolean> BOOLEAN_AS_STRING = new TypeAdapter<Boolean>() {
|
||||
@Override public Boolean read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
@Override public Boolean read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return Boolean.valueOf(reader.nextString());
|
||||
return Boolean.valueOf(in.nextString());
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, Boolean value) throws IOException {
|
||||
writer.value(value == null ? "null" : value.toString());
|
||||
@Override public void write(JsonWriter out, Boolean value) throws IOException {
|
||||
out.value(value == null ? "null" : value.toString());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory BOOLEAN_FACTORY
|
||||
public static final TypeAdapterFactory BOOLEAN_FACTORY
|
||||
= newFactory(boolean.class, Boolean.class, BOOLEAN);
|
||||
|
||||
public static final TypeAdapter<Number> BYTE = new TypeAdapter<Number>() {
|
||||
@Override
|
||||
public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Number read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
int intValue = reader.nextInt();
|
||||
int intValue = in.nextInt();
|
||||
return (byte) intValue;
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Number value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory BYTE_FACTORY
|
||||
public static final TypeAdapterFactory BYTE_FACTORY
|
||||
= newFactory(byte.class, Byte.class, BYTE);
|
||||
|
||||
public static final TypeAdapter<Number> SHORT = new TypeAdapter<Number>() {
|
||||
@Override
|
||||
public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Number read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (short) reader.nextInt();
|
||||
return (short) in.nextInt();
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Number value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory SHORT_FACTORY
|
||||
public static final TypeAdapterFactory SHORT_FACTORY
|
||||
= newFactory(short.class, Short.class, SHORT);
|
||||
|
||||
public static final TypeAdapter<Number> INTEGER = new TypeAdapter<Number>() {
|
||||
@Override
|
||||
public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Number read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return reader.nextInt();
|
||||
return in.nextInt();
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Number value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory INTEGER_FACTORY
|
||||
public static final TypeAdapterFactory INTEGER_FACTORY
|
||||
= newFactory(int.class, Integer.class, INTEGER);
|
||||
|
||||
public static final TypeAdapter<Number> LONG = new TypeAdapter<Number>() {
|
||||
@Override
|
||||
public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Number read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return reader.nextLong();
|
||||
return in.nextLong();
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Number value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory LONG_FACTORY
|
||||
= newFactory(long.class, Long.class, LONG);
|
||||
|
||||
public static final TypeAdapter<Number> FLOAT = new TypeAdapter<Number>() {
|
||||
@Override
|
||||
public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Number read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return (float) reader.nextDouble();
|
||||
return (float) in.nextDouble();
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Number value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory FLOAT_FACTORY
|
||||
= newFactory(float.class, Float.class, FLOAT);
|
||||
|
||||
public static final TypeAdapter<Number> DOUBLE = new TypeAdapter<Number>() {
|
||||
@Override
|
||||
public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Number read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return reader.nextDouble();
|
||||
return in.nextDouble();
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Number value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory DOUBLE_FACTORY
|
||||
= newFactory(double.class, Double.class, DOUBLE);
|
||||
|
||||
public static final TypeAdapter<Number> NUMBER = new TypeAdapter<Number>() {
|
||||
@Override
|
||||
public Number read(JsonReader reader) throws IOException {
|
||||
JsonToken jsonToken = reader.peek();
|
||||
public Number read(JsonReader in) throws IOException {
|
||||
JsonToken jsonToken = in.peek();
|
||||
switch (jsonToken) {
|
||||
case NULL:
|
||||
reader.nextNull();
|
||||
in.nextNull();
|
||||
return null;
|
||||
case NUMBER:
|
||||
return new LazilyParsedNumber(reader.nextString());
|
||||
return new LazilyParsedNumber(in.nextString());
|
||||
default:
|
||||
throw new JsonSyntaxException("Expecting number, got: " + jsonToken);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Number value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory NUMBER_FACTORY = newFactory(Number.class, NUMBER);
|
||||
public static final TypeAdapterFactory NUMBER_FACTORY = newFactory(Number.class, NUMBER);
|
||||
|
||||
public static final TypeAdapter<Character> CHARACTER = new TypeAdapter<Character>() {
|
||||
@Override
|
||||
public Character read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Character read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return reader.nextString().charAt(0);
|
||||
String str = in.nextString();
|
||||
if (str.length() != 1) {
|
||||
throw new JsonSyntaxException("Expecting character, got: " + str);
|
||||
}
|
||||
return str.charAt(0);
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Character value) throws IOException {
|
||||
writer.value(value == null ? null : String.valueOf(value));
|
||||
public void write(JsonWriter out, Character value) throws IOException {
|
||||
out.value(value == null ? null : String.valueOf(value));
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory CHARACTER_FACTORY
|
||||
public static final TypeAdapterFactory CHARACTER_FACTORY
|
||||
= newFactory(char.class, Character.class, CHARACTER);
|
||||
|
||||
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
|
||||
@Override
|
||||
public String read(JsonReader reader) throws IOException {
|
||||
JsonToken peek = reader.peek();
|
||||
public String read(JsonReader in) throws IOException {
|
||||
JsonToken peek = in.peek();
|
||||
if (peek == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
/* coerce booleans to strings for backwards compatibility */
|
||||
if (peek == JsonToken.BOOLEAN) {
|
||||
return Boolean.toString(reader.nextBoolean());
|
||||
return Boolean.toString(in.nextBoolean());
|
||||
}
|
||||
return reader.nextString();
|
||||
return in.nextString();
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, String value) throws IOException {
|
||||
writer.value(value);
|
||||
public void write(JsonWriter out, String value) throws IOException {
|
||||
out.value(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory STRING_FACTORY = newFactory(String.class, STRING);
|
||||
public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
|
||||
|
||||
public static final TypeAdapter<StringBuilder> STRING_BUILDER = new TypeAdapter<StringBuilder>() {
|
||||
@Override
|
||||
public StringBuilder read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public StringBuilder read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return new StringBuilder(reader.nextString());
|
||||
return new StringBuilder(in.nextString());
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, StringBuilder value) throws IOException {
|
||||
writer.value(value == null ? null : value.toString());
|
||||
public void write(JsonWriter out, StringBuilder value) throws IOException {
|
||||
out.value(value == null ? null : value.toString());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory STRING_BUILDER_FACTORY =
|
||||
public static final TypeAdapterFactory STRING_BUILDER_FACTORY =
|
||||
newFactory(StringBuilder.class, STRING_BUILDER);
|
||||
|
||||
public static final TypeAdapter<StringBuffer> STRING_BUFFER = new TypeAdapter<StringBuffer>() {
|
||||
@Override
|
||||
public StringBuffer read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public StringBuffer read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return new StringBuffer(reader.nextString());
|
||||
return new StringBuffer(in.nextString());
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, StringBuffer value) throws IOException {
|
||||
writer.value(value == null ? null : value.toString());
|
||||
public void write(JsonWriter out, StringBuffer value) throws IOException {
|
||||
out.value(value == null ? null : value.toString());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory STRING_BUFFER_FACTORY =
|
||||
public static final TypeAdapterFactory STRING_BUFFER_FACTORY =
|
||||
newFactory(StringBuffer.class, STRING_BUFFER);
|
||||
|
||||
public static final TypeAdapter<URL> URL = new TypeAdapter<URL>() {
|
||||
@Override
|
||||
public URL read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public URL read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
String nextString = reader.nextString();
|
||||
String nextString = in.nextString();
|
||||
return "null".equals(nextString) ? null : new URL(nextString);
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, URL value) throws IOException {
|
||||
writer.value(value == null ? null : value.toExternalForm());
|
||||
public void write(JsonWriter out, URL value) throws IOException {
|
||||
out.value(value == null ? null : value.toExternalForm());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory URL_FACTORY = newFactory(URL.class, URL);
|
||||
public static final TypeAdapterFactory URL_FACTORY = newFactory(URL.class, URL);
|
||||
|
||||
public static final TypeAdapter<URI> URI = new TypeAdapter<URI>() {
|
||||
@Override
|
||||
public URI read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public URI read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String nextString = reader.nextString();
|
||||
String nextString = in.nextString();
|
||||
return "null".equals(nextString) ? null : new URI(nextString);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, URI value) throws IOException {
|
||||
writer.value(value == null ? null : value.toASCIIString());
|
||||
public void write(JsonWriter out, URI value) throws IOException {
|
||||
out.value(value == null ? null : value.toASCIIString());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory URI_FACTORY = newFactory(URI.class, URI);
|
||||
public static final TypeAdapterFactory URI_FACTORY = newFactory(URI.class, URI);
|
||||
|
||||
public static final TypeAdapter<InetAddress> INET_ADDRESS = new TypeAdapter<InetAddress>() {
|
||||
@Override
|
||||
public InetAddress read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public InetAddress read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return InetAddress.getByName(reader.nextString());
|
||||
// regrettably, this should have included both the host name and the host address
|
||||
return InetAddress.getByName(in.nextString());
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, InetAddress value) throws IOException {
|
||||
writer.value(value == null ? null : value.getHostAddress());
|
||||
public void write(JsonWriter out, InetAddress value) throws IOException {
|
||||
out.value(value == null ? null : value.getHostAddress());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory INET_ADDRESS_FACTORY =
|
||||
public static final TypeAdapterFactory INET_ADDRESS_FACTORY =
|
||||
newTypeHierarchyFactory(InetAddress.class, INET_ADDRESS);
|
||||
|
||||
public static final TypeAdapter<UUID> UUID = new TypeAdapter<UUID>() {
|
||||
@Override
|
||||
public UUID read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public UUID read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return java.util.UUID.fromString(reader.nextString());
|
||||
return java.util.UUID.fromString(in.nextString());
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, UUID value) throws IOException {
|
||||
writer.value(value == null ? null : value.toString());
|
||||
public void write(JsonWriter out, UUID value) throws IOException {
|
||||
out.value(value == null ? null : value.toString());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory UUID_FACTORY = newFactory(UUID.class, UUID);
|
||||
public static final TypeAdapterFactory UUID_FACTORY = newFactory(UUID.class, UUID);
|
||||
|
||||
public static final TypeAdapter.Factory TIMESTAMP_FACTORY = new TypeAdapter.Factory() {
|
||||
public static final TypeAdapterFactory TIMESTAMP_FACTORY = new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
if (typeToken.getRawType() != Timestamp.class) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TypeAdapter<Date> dateTypeAdapter = context.getAdapter(Date.class);
|
||||
final TypeAdapter<Date> dateTypeAdapter = gson.getAdapter(Date.class);
|
||||
return (TypeAdapter<T>) new TypeAdapter<Timestamp>() {
|
||||
@Override public Timestamp read(JsonReader reader) throws IOException {
|
||||
Date date = dateTypeAdapter.read(reader);
|
||||
@Override public Timestamp read(JsonReader in) throws IOException {
|
||||
Date date = dateTypeAdapter.read(in);
|
||||
return date != null ? new Timestamp(date.getTime()) : null;
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, Timestamp value) throws IOException {
|
||||
dateTypeAdapter.write(writer, value);
|
||||
@Override public void write(JsonWriter out, Timestamp value) throws IOException {
|
||||
dateTypeAdapter.write(out, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -480,21 +496,21 @@ public final class TypeAdapters {
|
||||
private static final String SECOND = "second";
|
||||
|
||||
@Override
|
||||
public Calendar read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Calendar read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
reader.beginObject();
|
||||
in.beginObject();
|
||||
int year = 0;
|
||||
int month = 0;
|
||||
int dayOfMonth = 0;
|
||||
int hourOfDay = 0;
|
||||
int minute = 0;
|
||||
int second = 0;
|
||||
while (reader.peek() != JsonToken.END_OBJECT) {
|
||||
String name = reader.nextName();
|
||||
int value = reader.nextInt();
|
||||
while (in.peek() != JsonToken.END_OBJECT) {
|
||||
String name = in.nextName();
|
||||
int value = in.nextInt();
|
||||
if (YEAR.equals(name)) {
|
||||
year = value;
|
||||
} else if (MONTH.equals(name)) {
|
||||
@ -509,44 +525,44 @@ public final class TypeAdapters {
|
||||
second = value;
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
in.endObject();
|
||||
return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter writer, Calendar value) throws IOException {
|
||||
public void write(JsonWriter out, Calendar value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
writer.beginObject();
|
||||
writer.name(YEAR);
|
||||
writer.value(value.get(Calendar.YEAR));
|
||||
writer.name(MONTH);
|
||||
writer.value(value.get(Calendar.MONTH));
|
||||
writer.name(DAY_OF_MONTH);
|
||||
writer.value(value.get(Calendar.DAY_OF_MONTH));
|
||||
writer.name(HOUR_OF_DAY);
|
||||
writer.value(value.get(Calendar.HOUR_OF_DAY));
|
||||
writer.name(MINUTE);
|
||||
writer.value(value.get(Calendar.MINUTE));
|
||||
writer.name(SECOND);
|
||||
writer.value(value.get(Calendar.SECOND));
|
||||
writer.endObject();
|
||||
out.beginObject();
|
||||
out.name(YEAR);
|
||||
out.value(value.get(Calendar.YEAR));
|
||||
out.name(MONTH);
|
||||
out.value(value.get(Calendar.MONTH));
|
||||
out.name(DAY_OF_MONTH);
|
||||
out.value(value.get(Calendar.DAY_OF_MONTH));
|
||||
out.name(HOUR_OF_DAY);
|
||||
out.value(value.get(Calendar.HOUR_OF_DAY));
|
||||
out.name(MINUTE);
|
||||
out.value(value.get(Calendar.MINUTE));
|
||||
out.name(SECOND);
|
||||
out.value(value.get(Calendar.SECOND));
|
||||
out.endObject();
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory CALENDAR_FACTORY =
|
||||
public static final TypeAdapterFactory CALENDAR_FACTORY =
|
||||
newFactoryForMultipleTypes(Calendar.class, GregorianCalendar.class, CALENDAR);
|
||||
|
||||
public static final TypeAdapter<Locale> LOCALE = new TypeAdapter<Locale>() {
|
||||
@Override
|
||||
public Locale read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public Locale read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
String locale = reader.nextString();
|
||||
String locale = in.nextString();
|
||||
StringTokenizer tokenizer = new StringTokenizer(locale, "_");
|
||||
String language = null;
|
||||
String country = null;
|
||||
@ -569,41 +585,41 @@ public final class TypeAdapters {
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Locale value) throws IOException {
|
||||
writer.value(value == null ? null : value.toString());
|
||||
public void write(JsonWriter out, Locale value) throws IOException {
|
||||
out.value(value == null ? null : value.toString());
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory LOCALE_FACTORY = newFactory(Locale.class, LOCALE);
|
||||
public static final TypeAdapterFactory LOCALE_FACTORY = newFactory(Locale.class, LOCALE);
|
||||
|
||||
public static final TypeAdapter<JsonElement> JSON_ELEMENT = new TypeAdapter<JsonElement>() {
|
||||
@Override public JsonElement read(JsonReader reader) throws IOException {
|
||||
switch (reader.peek()) {
|
||||
@Override public JsonElement read(JsonReader in) throws IOException {
|
||||
switch (in.peek()) {
|
||||
case STRING:
|
||||
return new JsonPrimitive(reader.nextString());
|
||||
return new JsonPrimitive(in.nextString());
|
||||
case NUMBER:
|
||||
String number = reader.nextString();
|
||||
String number = in.nextString();
|
||||
return new JsonPrimitive(new LazilyParsedNumber(number));
|
||||
case BOOLEAN:
|
||||
return new JsonPrimitive(reader.nextBoolean());
|
||||
return new JsonPrimitive(in.nextBoolean());
|
||||
case NULL:
|
||||
reader.nextNull();
|
||||
in.nextNull();
|
||||
return JsonNull.INSTANCE;
|
||||
case BEGIN_ARRAY:
|
||||
JsonArray array = new JsonArray();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
array.add(read(reader));
|
||||
in.beginArray();
|
||||
while (in.hasNext()) {
|
||||
array.add(read(in));
|
||||
}
|
||||
reader.endArray();
|
||||
in.endArray();
|
||||
return array;
|
||||
case BEGIN_OBJECT:
|
||||
JsonObject object = new JsonObject();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
object.add(reader.nextName(), read(reader));
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
object.add(in.nextName(), read(in));
|
||||
}
|
||||
reader.endObject();
|
||||
in.endObject();
|
||||
return object;
|
||||
case END_DOCUMENT:
|
||||
case NAME:
|
||||
@ -614,33 +630,33 @@ public final class TypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, JsonElement value) throws IOException {
|
||||
@Override public void write(JsonWriter out, JsonElement value) throws IOException {
|
||||
if (value == null || value.isJsonNull()) {
|
||||
writer.nullValue();
|
||||
out.nullValue();
|
||||
} else if (value.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = value.getAsJsonPrimitive();
|
||||
if (primitive.isNumber()) {
|
||||
writer.value(primitive.getAsNumber());
|
||||
out.value(primitive.getAsNumber());
|
||||
} else if (primitive.isBoolean()) {
|
||||
writer.value(primitive.getAsBoolean());
|
||||
out.value(primitive.getAsBoolean());
|
||||
} else {
|
||||
writer.value(primitive.getAsString());
|
||||
out.value(primitive.getAsString());
|
||||
}
|
||||
|
||||
} else if (value.isJsonArray()) {
|
||||
writer.beginArray();
|
||||
out.beginArray();
|
||||
for (JsonElement e : value.getAsJsonArray()) {
|
||||
write(writer, e);
|
||||
write(out, e);
|
||||
}
|
||||
writer.endArray();
|
||||
out.endArray();
|
||||
|
||||
} else if (value.isJsonObject()) {
|
||||
writer.beginObject();
|
||||
out.beginObject();
|
||||
for (Map.Entry<String, JsonElement> e : value.getAsJsonObject().entrySet()) {
|
||||
writer.name(e.getKey());
|
||||
write(writer, e.getValue());
|
||||
out.name(e.getKey());
|
||||
write(out, e.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
out.endObject();
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Couldn't write " + value.getClass());
|
||||
@ -648,56 +664,74 @@ public final class TypeAdapters {
|
||||
}
|
||||
};
|
||||
|
||||
public static final TypeAdapter.Factory JSON_ELEMENT_FACTORY
|
||||
public static final TypeAdapterFactory JSON_ELEMENT_FACTORY
|
||||
= newFactory(JsonElement.class, JSON_ELEMENT);
|
||||
|
||||
private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
|
||||
private final Class<T> classOfT;
|
||||
private final Map<String, T> nameToConstant = new HashMap<String, T>();
|
||||
private final Map<T, String> constantToName = new HashMap<T, String>();
|
||||
|
||||
public EnumTypeAdapter(Class<T> classOfT) {
|
||||
this.classOfT = classOfT;
|
||||
try {
|
||||
for (T constant : classOfT.getEnumConstants()) {
|
||||
String name = constant.name();
|
||||
SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class);
|
||||
if (annotation != null) {
|
||||
name = annotation.value();
|
||||
}
|
||||
nameToConstant.put(name, constant);
|
||||
constantToName.put(constant, name);
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
public T read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull();
|
||||
public T read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return (T) Enum.valueOf((Class<T>) classOfT, reader.nextString());
|
||||
return nameToConstant.get(in.nextString());
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, T value) throws IOException {
|
||||
writer.value(value == null ? null : value.name());
|
||||
public void write(JsonWriter out, T value) throws IOException {
|
||||
out.value(value == null ? null : constantToName.get(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final TypeAdapter.Factory ENUM_FACTORY = newEnumTypeHierarchyFactory(Enum.class);
|
||||
public static final TypeAdapterFactory ENUM_FACTORY = newEnumTypeHierarchyFactory();
|
||||
|
||||
public static <TT> TypeAdapter.Factory newEnumTypeHierarchyFactory(final Class<TT> clazz) {
|
||||
return new TypeAdapter.Factory() {
|
||||
public static <TT> TypeAdapterFactory newEnumTypeHierarchyFactory() {
|
||||
return new TypeAdapterFactory() {
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
return clazz.isAssignableFrom(rawType)
|
||||
? (TypeAdapter<T>) new EnumTypeAdapter(rawType) : null;
|
||||
if (!Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) {
|
||||
return null;
|
||||
}
|
||||
if (!rawType.isEnum()) {
|
||||
rawType = rawType.getSuperclass(); // handle anonymous subclasses
|
||||
}
|
||||
return (TypeAdapter<T>) new EnumTypeAdapter(rawType);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <TT> TypeAdapter.Factory newFactory(
|
||||
public static <TT> TypeAdapterFactory newFactory(
|
||||
final TypeToken<TT> type, final TypeAdapter<TT> typeAdapter) {
|
||||
return new TypeAdapter.Factory() {
|
||||
return new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
return typeToken.equals(type) ? (TypeAdapter<T>) typeAdapter : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <TT> TypeAdapter.Factory newFactory(
|
||||
public static <TT> TypeAdapterFactory newFactory(
|
||||
final Class<TT> type, final TypeAdapter<TT> typeAdapter) {
|
||||
return new TypeAdapter.Factory() {
|
||||
return new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;
|
||||
}
|
||||
@Override public String toString() {
|
||||
@ -706,11 +740,11 @@ public final class TypeAdapters {
|
||||
};
|
||||
}
|
||||
|
||||
public static <TT> TypeAdapter.Factory newFactory(
|
||||
public static <TT> TypeAdapterFactory newFactory(
|
||||
final Class<TT> unboxed, final Class<TT> boxed, final TypeAdapter<? super TT> typeAdapter) {
|
||||
return new TypeAdapter.Factory() {
|
||||
return new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
return (rawType == unboxed || rawType == boxed) ? (TypeAdapter<T>) typeAdapter : null;
|
||||
}
|
||||
@ -721,11 +755,11 @@ public final class TypeAdapters {
|
||||
};
|
||||
}
|
||||
|
||||
public static <TT> TypeAdapter.Factory newFactoryForMultipleTypes(
|
||||
final Class<TT> base, final Class<? extends TT> sub, final TypeAdapter<? super TT> typeAdapter) {
|
||||
return new TypeAdapter.Factory() {
|
||||
public static <TT> TypeAdapterFactory newFactoryForMultipleTypes(final Class<TT> base,
|
||||
final Class<? extends TT> sub, final TypeAdapter<? super TT> typeAdapter) {
|
||||
return new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
return (rawType == base || rawType == sub) ? (TypeAdapter<T>) typeAdapter : null;
|
||||
}
|
||||
@ -736,11 +770,11 @@ public final class TypeAdapters {
|
||||
};
|
||||
}
|
||||
|
||||
public static <TT> TypeAdapter.Factory newTypeHierarchyFactory(
|
||||
public static <TT> TypeAdapterFactory newTypeHierarchyFactory(
|
||||
final Class<TT> clazz, final TypeAdapter<TT> typeAdapter) {
|
||||
return new TypeAdapter.Factory() {
|
||||
return new TypeAdapterFactory() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
return clazz.isAssignableFrom(typeToken.getRawType()) ? (TypeAdapter<T>) typeAdapter : null;
|
||||
}
|
||||
@Override public String toString() {
|
||||
@ -748,5 +782,4 @@ public final class TypeAdapters {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.reflect;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.reflect.TypeToken;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Preconditions;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.$Gson$Types;
|
||||
|
||||
@ -46,7 +47,6 @@ import java.util.Map;
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public class TypeToken<T> {
|
||||
|
||||
final Class<? super T> rawType;
|
||||
final Type type;
|
||||
final int hashCode;
|
||||
|
@ -16,12 +16,18 @@
|
||||
|
||||
package com.massivecraft.mcore2.lib.gson.stream;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonScope;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonToken;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.MalformedJsonException;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.StringPool;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.JsonReaderInternalAccess;
|
||||
import com.massivecraft.mcore2.lib.gson.internal.bind.JsonTreeReader;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reads a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
|
||||
@ -32,8 +38,8 @@ import java.util.List;
|
||||
* Within JSON objects, name/value pairs are represented by a single token.
|
||||
*
|
||||
* <h3>Parsing JSON</h3>
|
||||
* To create a recursive descent parser your own JSON streams, first create an
|
||||
* entry point method that creates a {@code JsonReader}.
|
||||
* To create a recursive descent parser for your own JSON streams, first create
|
||||
* an entry point method that creates a {@code JsonReader}.
|
||||
*
|
||||
* <p>Next, create handler methods for each structure in your JSON text. You'll
|
||||
* need a method for each object type and for each array type.
|
||||
@ -86,7 +92,11 @@ import java.util.List;
|
||||
*
|
||||
* public List<Message> readJsonStream(InputStream in) throws IOException {
|
||||
* JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
|
||||
* return readMessagesArray(reader);
|
||||
* try {
|
||||
* return readMessagesArray(reader);
|
||||
* } finally {
|
||||
* reader.close();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* public List<Message> readMessagesArray(JsonReader reader) throws IOException {
|
||||
@ -188,6 +198,9 @@ public class JsonReader implements Closeable {
|
||||
/** The only non-execute prefix this parser permits */
|
||||
private static final char[] NON_EXECUTE_PREFIX = ")]}'\n".toCharArray();
|
||||
|
||||
private static final String TRUE = "true";
|
||||
private static final String FALSE = "false";
|
||||
|
||||
private final StringPool stringPool = new StringPool();
|
||||
|
||||
/** The input JSON. */
|
||||
@ -199,6 +212,8 @@ public class JsonReader implements Closeable {
|
||||
/**
|
||||
* Use a manual buffer to easily read and unread upcoming characters, and
|
||||
* also so we can create strings without an intermediate StringBuilder.
|
||||
* We decode literals directly out of this buffer, so it must be at least as
|
||||
* long as the longest token that can be reported as a number.
|
||||
*/
|
||||
private final char[] buffer = new char[1024];
|
||||
private int pos = 0;
|
||||
@ -210,32 +225,31 @@ public class JsonReader implements Closeable {
|
||||
private int bufferStartLine = 1;
|
||||
private int bufferStartColumn = 1;
|
||||
|
||||
private final List<JsonScope> stack = new ArrayList<JsonScope>();
|
||||
/*
|
||||
* The nesting stack. Using a manual array rather than an ArrayList saves 20%.
|
||||
*/
|
||||
private JsonScope[] stack = new JsonScope[32];
|
||||
private int stackSize = 0;
|
||||
{
|
||||
push(JsonScope.EMPTY_DOCUMENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* True if we've already read the next token. If we have, the string value
|
||||
* for that token will be assigned to {@code value} if such a string value
|
||||
* exists. And the token type will be assigned to {@code token} if the token
|
||||
* type is known. The token type may be null for literals, since we derive
|
||||
* that lazily.
|
||||
*/
|
||||
private boolean hasToken;
|
||||
|
||||
/**
|
||||
* The type of the next token to be returned by {@link #peek} and {@link
|
||||
* #advance}, or {@code null} if it is unknown and must first be derived
|
||||
* from {@code value}. This value is undefined if {@code hasToken} is false.
|
||||
* #advance}. If null, peek() will assign a value.
|
||||
*/
|
||||
private JsonToken token;
|
||||
|
||||
/** The text of the next name. */
|
||||
private String name;
|
||||
|
||||
/** The text of the next literal value. */
|
||||
/*
|
||||
* For the next literal value, we may have the text value, or the position
|
||||
* and length in the buffer.
|
||||
*/
|
||||
private String value;
|
||||
private int valuePos;
|
||||
private int valueLength;
|
||||
|
||||
/** True if we're currently handling a skipValue() call. */
|
||||
private boolean skipping = false;
|
||||
@ -326,9 +340,10 @@ public class JsonReader implements Closeable {
|
||||
* Consumes {@code expected}.
|
||||
*/
|
||||
private void expect(JsonToken expected) throws IOException {
|
||||
quickPeek();
|
||||
peek();
|
||||
if (token != expected) {
|
||||
throw new IllegalStateException("Expected " + expected + " but was " + peek());
|
||||
throw new IllegalStateException("Expected " + expected + " but was " + peek()
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
advance();
|
||||
}
|
||||
@ -337,7 +352,7 @@ public class JsonReader implements Closeable {
|
||||
* Returns true if the current array or object has another element.
|
||||
*/
|
||||
public boolean hasNext() throws IOException {
|
||||
quickPeek();
|
||||
peek();
|
||||
return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
|
||||
}
|
||||
|
||||
@ -345,34 +360,20 @@ public class JsonReader implements Closeable {
|
||||
* Returns the type of the next token without consuming it.
|
||||
*/
|
||||
public JsonToken peek() throws IOException {
|
||||
quickPeek();
|
||||
|
||||
if (token == null) {
|
||||
decodeLiteral();
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that a token is ready. After this call either {@code token} or
|
||||
* {@code value} will be non-null. To ensure {@code token} has a definitive
|
||||
* value, use {@link #peek()}
|
||||
*/
|
||||
private JsonToken quickPeek() throws IOException {
|
||||
if (hasToken) {
|
||||
if (token != null) {
|
||||
return token;
|
||||
}
|
||||
|
||||
switch (peekStack()) {
|
||||
switch (stack[stackSize - 1]) {
|
||||
case EMPTY_DOCUMENT:
|
||||
if (lenient) {
|
||||
consumeNonExecutePrefix();
|
||||
}
|
||||
replaceTop(JsonScope.NONEMPTY_DOCUMENT);
|
||||
stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
|
||||
JsonToken firstToken = nextValue();
|
||||
if (!lenient && firstToken != JsonToken.BEGIN_ARRAY && firstToken != JsonToken.BEGIN_OBJECT) {
|
||||
syntaxError("Expected JSON document to start with '[' or '{'");
|
||||
if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
|
||||
throw new IOException("Expected JSON document to start with '[' or '{' but was " + token
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
return firstToken;
|
||||
case EMPTY_ARRAY:
|
||||
@ -386,16 +387,15 @@ public class JsonReader implements Closeable {
|
||||
case NONEMPTY_OBJECT:
|
||||
return nextInObject(false);
|
||||
case NONEMPTY_DOCUMENT:
|
||||
try {
|
||||
JsonToken token = nextValue();
|
||||
if (lenient) {
|
||||
return token;
|
||||
}
|
||||
throw syntaxError("Expected EOF");
|
||||
} catch (EOFException e) {
|
||||
hasToken = true; // TODO: avoid throwing here?
|
||||
return token = JsonToken.END_DOCUMENT;
|
||||
int c = nextNonWhitespace(false);
|
||||
if (c == -1) {
|
||||
return JsonToken.END_DOCUMENT;
|
||||
}
|
||||
pos--;
|
||||
if (!lenient) {
|
||||
throw syntaxError("Expected EOF");
|
||||
}
|
||||
return nextValue();
|
||||
case CLOSED:
|
||||
throw new IllegalStateException("JsonReader is closed");
|
||||
default:
|
||||
@ -408,7 +408,7 @@ public class JsonReader implements Closeable {
|
||||
*/
|
||||
private void consumeNonExecutePrefix() throws IOException {
|
||||
// fast forward through the leading whitespace
|
||||
nextNonWhitespace();
|
||||
nextNonWhitespace(true);
|
||||
pos--;
|
||||
|
||||
if (pos + NON_EXECUTE_PREFIX.length > limit && !fillBuffer(NON_EXECUTE_PREFIX.length)) {
|
||||
@ -429,10 +429,9 @@ public class JsonReader implements Closeable {
|
||||
* Advances the cursor in the JSON stream to the next token.
|
||||
*/
|
||||
private JsonToken advance() throws IOException {
|
||||
quickPeek();
|
||||
peek();
|
||||
|
||||
JsonToken result = token;
|
||||
hasToken = false;
|
||||
token = null;
|
||||
value = null;
|
||||
name = null;
|
||||
@ -447,9 +446,10 @@ public class JsonReader implements Closeable {
|
||||
* name.
|
||||
*/
|
||||
public String nextName() throws IOException {
|
||||
quickPeek();
|
||||
peek();
|
||||
if (token != JsonToken.NAME) {
|
||||
throw new IllegalStateException("Expected a name but was " + peek());
|
||||
throw new IllegalStateException("Expected a name but was " + peek()
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
String result = name;
|
||||
advance();
|
||||
@ -466,8 +466,9 @@ public class JsonReader implements Closeable {
|
||||
*/
|
||||
public String nextString() throws IOException {
|
||||
peek();
|
||||
if (value == null || (token != JsonToken.STRING && token != JsonToken.NUMBER)) {
|
||||
throw new IllegalStateException("Expected a string but was " + peek());
|
||||
if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
|
||||
throw new IllegalStateException("Expected a string but was " + peek()
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
String result = value;
|
||||
@ -483,20 +484,13 @@ public class JsonReader implements Closeable {
|
||||
* this reader is closed.
|
||||
*/
|
||||
public boolean nextBoolean() throws IOException {
|
||||
quickPeek();
|
||||
if (value == null || token == JsonToken.STRING) {
|
||||
throw new IllegalStateException("Expected a boolean but was " + peek());
|
||||
}
|
||||
|
||||
boolean result;
|
||||
if (value.equalsIgnoreCase("true")) {
|
||||
result = true;
|
||||
} else if (value.equalsIgnoreCase("false")) {
|
||||
result = false;
|
||||
} else {
|
||||
throw new IllegalStateException("Not a boolean: " + value);
|
||||
peek();
|
||||
if (token != JsonToken.BOOLEAN) {
|
||||
throw new IllegalStateException("Expected a boolean but was " + token
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
boolean result = (value == TRUE);
|
||||
advance();
|
||||
return result;
|
||||
}
|
||||
@ -509,13 +503,10 @@ public class JsonReader implements Closeable {
|
||||
* reader is closed.
|
||||
*/
|
||||
public void nextNull() throws IOException {
|
||||
quickPeek();
|
||||
if (value == null || token == JsonToken.STRING) {
|
||||
throw new IllegalStateException("Expected null but was " + peek());
|
||||
}
|
||||
|
||||
if (!value.equalsIgnoreCase("null")) {
|
||||
throw new IllegalStateException("Not a null: " + value);
|
||||
peek();
|
||||
if (token != JsonToken.NULL) {
|
||||
throw new IllegalStateException("Expected null but was " + token
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
advance();
|
||||
@ -524,26 +515,28 @@ public class JsonReader implements Closeable {
|
||||
/**
|
||||
* Returns the {@link JsonToken#NUMBER double} value of the next token,
|
||||
* consuming it. If the next token is a string, this method will attempt to
|
||||
* parse it as a double.
|
||||
* parse it as a double using {@link Double#parseDouble(String)}.
|
||||
*
|
||||
* @throws IllegalStateException if the next token is not a literal value.
|
||||
* @throws NumberFormatException if the next literal value cannot be parsed
|
||||
* as a double, or is non-finite.
|
||||
*/
|
||||
public double nextDouble() throws IOException {
|
||||
quickPeek();
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Expected a double but was " + peek());
|
||||
peek();
|
||||
if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
|
||||
throw new IllegalStateException("Expected a double but was " + token
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
double result = Double.parseDouble(value);
|
||||
|
||||
if ((result >= 1.0d && value.startsWith("0"))) {
|
||||
throw new NumberFormatException("JSON forbids octal prefixes: " + value);
|
||||
throw new MalformedJsonException("JSON forbids octal prefixes: " + value
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {
|
||||
throw new NumberFormatException("JSON forbids NaN and infinities: " + value);
|
||||
throw new MalformedJsonException("JSON forbids NaN and infinities: " + value
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
advance();
|
||||
@ -561,9 +554,10 @@ public class JsonReader implements Closeable {
|
||||
* as a number, or exactly represented as a long.
|
||||
*/
|
||||
public long nextLong() throws IOException {
|
||||
quickPeek();
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Expected a long but was " + peek());
|
||||
peek();
|
||||
if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
|
||||
throw new IllegalStateException("Expected a long but was " + token
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
long result;
|
||||
@ -573,12 +567,14 @@ public class JsonReader implements Closeable {
|
||||
double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
|
||||
result = (long) asDouble;
|
||||
if (result != asDouble) {
|
||||
throw new NumberFormatException(value);
|
||||
throw new NumberFormatException("Expected a long but was " + value
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
}
|
||||
|
||||
if (result >= 1L && value.startsWith("0")) {
|
||||
throw new NumberFormatException("JSON forbids octal prefixes: " + value);
|
||||
throw new MalformedJsonException("JSON forbids octal prefixes: " + value
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
advance();
|
||||
@ -596,9 +592,10 @@ public class JsonReader implements Closeable {
|
||||
* as a number, or exactly represented as an int.
|
||||
*/
|
||||
public int nextInt() throws IOException {
|
||||
quickPeek();
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Expected an int but was " + peek());
|
||||
peek();
|
||||
if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
|
||||
throw new IllegalStateException("Expected an int but was " + token
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
int result;
|
||||
@ -608,12 +605,14 @@ public class JsonReader implements Closeable {
|
||||
double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
|
||||
result = (int) asDouble;
|
||||
if (result != asDouble) {
|
||||
throw new NumberFormatException(value);
|
||||
throw new NumberFormatException("Expected an int but was " + value
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
}
|
||||
|
||||
if (result >= 1L && value.startsWith("0")) {
|
||||
throw new NumberFormatException("JSON forbids octal prefixes: " + value);
|
||||
throw new MalformedJsonException("JSON forbids octal prefixes: " + value
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
}
|
||||
|
||||
advance();
|
||||
@ -624,11 +623,10 @@ public class JsonReader implements Closeable {
|
||||
* Closes this JSON reader and the underlying {@link Reader}.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
hasToken = false;
|
||||
value = null;
|
||||
token = null;
|
||||
stack.clear();
|
||||
stack.add(JsonScope.CLOSED);
|
||||
stack[0] = JsonScope.CLOSED;
|
||||
stackSize = 1;
|
||||
in.close();
|
||||
}
|
||||
|
||||
@ -654,35 +652,24 @@ public class JsonReader implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
private JsonScope peekStack() {
|
||||
return stack.get(stack.size() - 1);
|
||||
}
|
||||
|
||||
private JsonScope pop() {
|
||||
return stack.remove(stack.size() - 1);
|
||||
}
|
||||
|
||||
private void push(JsonScope newTop) {
|
||||
stack.add(newTop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the value on the top of the stack with the given value.
|
||||
*/
|
||||
private void replaceTop(JsonScope newTop) {
|
||||
stack.set(stack.size() - 1, newTop);
|
||||
if (stackSize == stack.length) {
|
||||
JsonScope[] newStack = new JsonScope[stackSize * 2];
|
||||
System.arraycopy(stack, 0, newStack, 0, stackSize);
|
||||
stack = newStack;
|
||||
}
|
||||
stack[stackSize++] = newTop;
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
private JsonToken nextInArray(boolean firstElement) throws IOException {
|
||||
if (firstElement) {
|
||||
replaceTop(JsonScope.NONEMPTY_ARRAY);
|
||||
stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
|
||||
} else {
|
||||
/* Look for a comma before each element after the first element. */
|
||||
switch (nextNonWhitespace()) {
|
||||
switch (nextNonWhitespace(true)) {
|
||||
case ']':
|
||||
pop();
|
||||
hasToken = true;
|
||||
stackSize--;
|
||||
return token = JsonToken.END_ARRAY;
|
||||
case ';':
|
||||
checkLenient(); // fall-through
|
||||
@ -693,11 +680,10 @@ public class JsonReader implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
switch (nextNonWhitespace()) {
|
||||
switch (nextNonWhitespace(true)) {
|
||||
case ']':
|
||||
if (firstElement) {
|
||||
pop();
|
||||
hasToken = true;
|
||||
stackSize--;
|
||||
return token = JsonToken.END_ARRAY;
|
||||
}
|
||||
// fall-through to handle ",]"
|
||||
@ -706,7 +692,6 @@ public class JsonReader implements Closeable {
|
||||
/* In lenient mode, a 0-length literal means 'null' */
|
||||
checkLenient();
|
||||
pos--;
|
||||
hasToken = true;
|
||||
value = "null";
|
||||
return token = JsonToken.NULL;
|
||||
default:
|
||||
@ -724,19 +709,17 @@ public class JsonReader implements Closeable {
|
||||
*/
|
||||
if (firstElement) {
|
||||
/* Peek to see if this is the empty object. */
|
||||
switch (nextNonWhitespace()) {
|
||||
switch (nextNonWhitespace(true)) {
|
||||
case '}':
|
||||
pop();
|
||||
hasToken = true;
|
||||
stackSize--;
|
||||
return token = JsonToken.END_OBJECT;
|
||||
default:
|
||||
pos--;
|
||||
}
|
||||
} else {
|
||||
switch (nextNonWhitespace()) {
|
||||
switch (nextNonWhitespace(true)) {
|
||||
case '}':
|
||||
pop();
|
||||
hasToken = true;
|
||||
stackSize--;
|
||||
return token = JsonToken.END_OBJECT;
|
||||
case ';':
|
||||
case ',':
|
||||
@ -747,7 +730,7 @@ public class JsonReader implements Closeable {
|
||||
}
|
||||
|
||||
/* Read the name. */
|
||||
int quote = nextNonWhitespace();
|
||||
int quote = nextNonWhitespace(true);
|
||||
switch (quote) {
|
||||
case '\'':
|
||||
checkLenient(); // fall-through
|
||||
@ -757,14 +740,13 @@ public class JsonReader implements Closeable {
|
||||
default:
|
||||
checkLenient();
|
||||
pos--;
|
||||
name = nextLiteral();
|
||||
name = nextLiteral(false);
|
||||
if (name.length() == 0) {
|
||||
throw syntaxError("Expected name");
|
||||
}
|
||||
}
|
||||
|
||||
replaceTop(JsonScope.DANGLING_NAME);
|
||||
hasToken = true;
|
||||
stack[stackSize - 1] = JsonScope.DANGLING_NAME;
|
||||
return token = JsonToken.NAME;
|
||||
}
|
||||
|
||||
@ -773,7 +755,7 @@ public class JsonReader implements Closeable {
|
||||
* Read the name/value separator. Usually a colon ':'. In lenient mode
|
||||
* we also accept an equals sign '=', or an arrow "=>".
|
||||
*/
|
||||
switch (nextNonWhitespace()) {
|
||||
switch (nextNonWhitespace(true)) {
|
||||
case ':':
|
||||
break;
|
||||
case '=':
|
||||
@ -786,29 +768,26 @@ public class JsonReader implements Closeable {
|
||||
throw syntaxError("Expected ':'");
|
||||
}
|
||||
|
||||
replaceTop(JsonScope.NONEMPTY_OBJECT);
|
||||
stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
|
||||
return nextValue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
private JsonToken nextValue() throws IOException {
|
||||
int c = nextNonWhitespace();
|
||||
int c = nextNonWhitespace(true);
|
||||
switch (c) {
|
||||
case '{':
|
||||
push(JsonScope.EMPTY_OBJECT);
|
||||
hasToken = true;
|
||||
return token = JsonToken.BEGIN_OBJECT;
|
||||
|
||||
case '[':
|
||||
push(JsonScope.EMPTY_ARRAY);
|
||||
hasToken = true;
|
||||
return token = JsonToken.BEGIN_ARRAY;
|
||||
|
||||
case '\'':
|
||||
checkLenient(); // fall-through
|
||||
case '"':
|
||||
value = nextString((char) c);
|
||||
hasToken = true;
|
||||
return token = JsonToken.STRING;
|
||||
|
||||
default:
|
||||
@ -823,15 +802,22 @@ public class JsonReader implements Closeable {
|
||||
* false.
|
||||
*/
|
||||
private boolean fillBuffer(int minimum) throws IOException {
|
||||
char[] buffer = this.buffer;
|
||||
|
||||
// Before clobbering the old characters, update where buffer starts
|
||||
for (int i = 0; i < pos; i++) {
|
||||
// Using locals here saves ~2%.
|
||||
int line = bufferStartLine;
|
||||
int column = bufferStartColumn;
|
||||
for (int i = 0, p = pos; i < p; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
bufferStartLine++;
|
||||
bufferStartColumn = 1;
|
||||
line++;
|
||||
column = 1;
|
||||
} else {
|
||||
bufferStartColumn++;
|
||||
column++;
|
||||
}
|
||||
}
|
||||
bufferStartLine = line;
|
||||
bufferStartColumn = column;
|
||||
|
||||
if (limit != pos) {
|
||||
limit -= pos;
|
||||
@ -880,9 +866,29 @@ public class JsonReader implements Closeable {
|
||||
return result;
|
||||
}
|
||||
|
||||
private int nextNonWhitespace() throws IOException {
|
||||
while (pos < limit || fillBuffer(1)) {
|
||||
int c = buffer[pos++];
|
||||
private int nextNonWhitespace(boolean throwOnEof) throws IOException {
|
||||
/*
|
||||
* This code uses ugly local variables 'p' and 'l' representing the 'pos'
|
||||
* and 'limit' fields respectively. Using locals rather than fields saves
|
||||
* a few field reads for each whitespace character in a pretty-printed
|
||||
* document, resulting in a 5% speedup. We need to flush 'p' to its field
|
||||
* before any (potentially indirect) call to fillBuffer() and reread both
|
||||
* 'p' and 'l' after any (potentially indirect) call to the same method.
|
||||
*/
|
||||
char[] buffer = this.buffer;
|
||||
int p = pos;
|
||||
int l = limit;
|
||||
while (true) {
|
||||
if (p == l) {
|
||||
pos = p;
|
||||
if (!fillBuffer(1)) {
|
||||
break;
|
||||
}
|
||||
p = pos;
|
||||
l = limit;
|
||||
}
|
||||
|
||||
int c = buffer[p++];
|
||||
switch (c) {
|
||||
case '\t':
|
||||
case ' ':
|
||||
@ -891,7 +897,8 @@ public class JsonReader implements Closeable {
|
||||
continue;
|
||||
|
||||
case '/':
|
||||
if (pos == limit && !fillBuffer(1)) {
|
||||
pos = p;
|
||||
if (p == l && !fillBuffer(1)) {
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -904,13 +911,16 @@ public class JsonReader implements Closeable {
|
||||
if (!skipTo("*/")) {
|
||||
throw syntaxError("Unterminated comment");
|
||||
}
|
||||
pos += 2;
|
||||
p = pos + 2;
|
||||
l = limit;
|
||||
continue;
|
||||
|
||||
case '/':
|
||||
// skip a // end-of-line comment
|
||||
pos++;
|
||||
skipToEndOfLine();
|
||||
p = pos;
|
||||
l = limit;
|
||||
continue;
|
||||
|
||||
default:
|
||||
@ -918,6 +928,7 @@ public class JsonReader implements Closeable {
|
||||
}
|
||||
|
||||
case '#':
|
||||
pos = p;
|
||||
/*
|
||||
* Skip a # hash end-of-line comment. The JSON RFC doesn't
|
||||
* specify this behaviour, but it's required to parse
|
||||
@ -925,13 +936,21 @@ public class JsonReader implements Closeable {
|
||||
*/
|
||||
checkLenient();
|
||||
skipToEndOfLine();
|
||||
p = pos;
|
||||
l = limit;
|
||||
continue;
|
||||
|
||||
default:
|
||||
pos = p;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
throw new EOFException("End of input");
|
||||
if (throwOnEof) {
|
||||
throw new EOFException("End of input"
|
||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkLenient() throws IOException {
|
||||
@ -978,62 +997,77 @@ public class JsonReader implements Closeable {
|
||||
* malformed.
|
||||
*/
|
||||
private String nextString(char quote) throws IOException {
|
||||
// Like nextNonWhitespace, this uses locals 'p' and 'l' to save inner-loop field access.
|
||||
char[] buffer = this.buffer;
|
||||
StringBuilder builder = null;
|
||||
do {
|
||||
while (true) {
|
||||
int p = pos;
|
||||
int l = limit;
|
||||
/* the index of the first character not yet appended to the builder. */
|
||||
int start = pos;
|
||||
while (pos < limit) {
|
||||
int c = buffer[pos++];
|
||||
int start = p;
|
||||
while (p < l) {
|
||||
int c = buffer[p++];
|
||||
|
||||
if (c == quote) {
|
||||
pos = p;
|
||||
if (skipping) {
|
||||
return "skipped!";
|
||||
} else if (builder == null) {
|
||||
return stringPool.get(buffer, start, pos - start - 1);
|
||||
return stringPool.get(buffer, start, p - start - 1);
|
||||
} else {
|
||||
builder.append(buffer, start, pos - start - 1);
|
||||
builder.append(buffer, start, p - start - 1);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
} else if (c == '\\') {
|
||||
pos = p;
|
||||
if (builder == null) {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
builder.append(buffer, start, pos - start - 1);
|
||||
builder.append(buffer, start, p - start - 1);
|
||||
builder.append(readEscapeCharacter());
|
||||
start = pos;
|
||||
p = pos;
|
||||
l = limit;
|
||||
start = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (builder == null) {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
builder.append(buffer, start, pos - start);
|
||||
} while (fillBuffer(1));
|
||||
|
||||
throw syntaxError("Unterminated string");
|
||||
builder.append(buffer, start, p - start);
|
||||
pos = p;
|
||||
if (!fillBuffer(1)) {
|
||||
throw syntaxError("Unterminated string");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string up to but not including any delimiter characters. This
|
||||
* Reads the value up to but not including any delimiter characters. This
|
||||
* does not consume the delimiter character.
|
||||
*
|
||||
* @param assignOffsetsOnly true for this method to only set the valuePos
|
||||
* and valueLength fields and return a null result. This only works if
|
||||
* the literal is short; a string is returned otherwise.
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
private String nextLiteral() throws IOException {
|
||||
private String nextLiteral(boolean assignOffsetsOnly) throws IOException {
|
||||
StringBuilder builder = null;
|
||||
do {
|
||||
/* the index of the first character not yet appended to the builder. */
|
||||
int start = pos;
|
||||
while (pos < limit) {
|
||||
int c = buffer[pos++];
|
||||
switch (c) {
|
||||
valuePos = -1;
|
||||
valueLength = 0;
|
||||
int i = 0;
|
||||
|
||||
findNonLiteralCharacter:
|
||||
while (true) {
|
||||
for (; pos + i < limit; i++) {
|
||||
switch (buffer[pos + i]) {
|
||||
case '/':
|
||||
case '\\':
|
||||
case ';':
|
||||
case '#':
|
||||
case '=':
|
||||
checkLenient(); // fall-through
|
||||
|
||||
checkLenient(); // fall-through
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
@ -1045,25 +1079,52 @@ public class JsonReader implements Closeable {
|
||||
case '\f':
|
||||
case '\r':
|
||||
case '\n':
|
||||
pos--;
|
||||
if (skipping) {
|
||||
return "skipped!";
|
||||
} else if (builder == null) {
|
||||
return stringPool.get(buffer, start, pos - start);
|
||||
} else {
|
||||
builder.append(buffer, start, pos - start);
|
||||
return builder.toString();
|
||||
}
|
||||
break findNonLiteralCharacter;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to load the entire literal into the buffer at once. If
|
||||
* we run out of input, add a non-literal character at the end so
|
||||
* that decoding doesn't need to do bounds checks.
|
||||
*/
|
||||
if (i < buffer.length) {
|
||||
if (fillBuffer(i + 1)) {
|
||||
continue;
|
||||
} else {
|
||||
buffer[limit] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// use a StringBuilder when the value is too long. It must be an unquoted string.
|
||||
if (builder == null) {
|
||||
builder = new StringBuilder();
|
||||
}
|
||||
builder.append(buffer, start, pos - start);
|
||||
} while (fillBuffer(1));
|
||||
builder.append(buffer, pos, i);
|
||||
valueLength += i;
|
||||
pos += i;
|
||||
i = 0;
|
||||
if (!fillBuffer(1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
String result;
|
||||
if (assignOffsetsOnly && builder == null) {
|
||||
valuePos = pos;
|
||||
result = null;
|
||||
} else if (skipping) {
|
||||
result = "skipped!";
|
||||
} else if (builder == null) {
|
||||
result = stringPool.get(buffer, pos, i);
|
||||
} else {
|
||||
builder.append(buffer, pos, i);
|
||||
result = builder.toString();
|
||||
}
|
||||
valueLength += i;
|
||||
pos += i;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
@ -1090,9 +1151,23 @@ public class JsonReader implements Closeable {
|
||||
if (pos + 4 > limit && !fillBuffer(4)) {
|
||||
throw syntaxError("Unterminated escape sequence");
|
||||
}
|
||||
String hex = stringPool.get(buffer, pos, 4);
|
||||
// Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16);
|
||||
char result = 0;
|
||||
for (int i = pos, end = i + 4; i < end; i++) {
|
||||
char c = buffer[i];
|
||||
result <<= 4;
|
||||
if (c >= '0' && c <= '9') {
|
||||
result += (c - '0');
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
result += (c - 'a' + 10);
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
result += (c - 'A' + 10);
|
||||
} else {
|
||||
throw new NumberFormatException("\\u" + stringPool.get(buffer, pos, 4));
|
||||
}
|
||||
}
|
||||
pos += 4;
|
||||
return (char) Integer.parseInt(hex, 16);
|
||||
return result;
|
||||
|
||||
case 't':
|
||||
return '\t';
|
||||
@ -1121,32 +1196,103 @@ public class JsonReader implements Closeable {
|
||||
* Reads a null, boolean, numeric or unquoted string literal value.
|
||||
*/
|
||||
private JsonToken readLiteral() throws IOException {
|
||||
String literal = nextLiteral();
|
||||
if (literal.length() == 0) {
|
||||
value = nextLiteral(true);
|
||||
if (valueLength == 0) {
|
||||
throw syntaxError("Expected literal value");
|
||||
}
|
||||
value = literal;
|
||||
hasToken = true;
|
||||
return token = null; // use decodeLiteral() to get the token type
|
||||
token = decodeLiteral();
|
||||
if (token == JsonToken.STRING) {
|
||||
checkLenient();
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@code nextToken} based on the value of {@code nextValue}.
|
||||
*/
|
||||
private void decodeLiteral() throws IOException {
|
||||
if (value.equalsIgnoreCase("null")) {
|
||||
token = JsonToken.NULL;
|
||||
} else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
|
||||
token = JsonToken.BOOLEAN;
|
||||
private JsonToken decodeLiteral() throws IOException {
|
||||
if (valuePos == -1) {
|
||||
// it was too long to fit in the buffer so it can only be a string
|
||||
return JsonToken.STRING;
|
||||
} else if (valueLength == 4
|
||||
&& ('n' == buffer[valuePos ] || 'N' == buffer[valuePos ])
|
||||
&& ('u' == buffer[valuePos + 1] || 'U' == buffer[valuePos + 1])
|
||||
&& ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])
|
||||
&& ('l' == buffer[valuePos + 3] || 'L' == buffer[valuePos + 3])) {
|
||||
value = "null";
|
||||
return JsonToken.NULL;
|
||||
} else if (valueLength == 4
|
||||
&& ('t' == buffer[valuePos ] || 'T' == buffer[valuePos ])
|
||||
&& ('r' == buffer[valuePos + 1] || 'R' == buffer[valuePos + 1])
|
||||
&& ('u' == buffer[valuePos + 2] || 'U' == buffer[valuePos + 2])
|
||||
&& ('e' == buffer[valuePos + 3] || 'E' == buffer[valuePos + 3])) {
|
||||
value = TRUE;
|
||||
return JsonToken.BOOLEAN;
|
||||
} else if (valueLength == 5
|
||||
&& ('f' == buffer[valuePos ] || 'F' == buffer[valuePos ])
|
||||
&& ('a' == buffer[valuePos + 1] || 'A' == buffer[valuePos + 1])
|
||||
&& ('l' == buffer[valuePos + 2] || 'L' == buffer[valuePos + 2])
|
||||
&& ('s' == buffer[valuePos + 3] || 'S' == buffer[valuePos + 3])
|
||||
&& ('e' == buffer[valuePos + 4] || 'E' == buffer[valuePos + 4])) {
|
||||
value = FALSE;
|
||||
return JsonToken.BOOLEAN;
|
||||
} else {
|
||||
try {
|
||||
Double.parseDouble(value); // this work could potentially be cached
|
||||
token = JsonToken.NUMBER;
|
||||
} catch (NumberFormatException ignored) {
|
||||
// this must be an unquoted string
|
||||
checkLenient();
|
||||
token = JsonToken.STRING;
|
||||
value = stringPool.get(buffer, valuePos, valueLength);
|
||||
return decodeNumber(buffer, valuePos, valueLength);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the characters is a JSON number. Numbers are of the
|
||||
* form -12.34e+56. Fractional and exponential parts are optional. Leading
|
||||
* zeroes are not allowed in the value or exponential part, but are allowed
|
||||
* in the fraction.
|
||||
*/
|
||||
private JsonToken decodeNumber(char[] chars, int offset, int length) {
|
||||
int i = offset;
|
||||
int c = chars[i];
|
||||
|
||||
if (c == '-') {
|
||||
c = chars[++i];
|
||||
}
|
||||
|
||||
if (c == '0') {
|
||||
c = chars[++i];
|
||||
} else if (c >= '1' && c <= '9') {
|
||||
c = chars[++i];
|
||||
while (c >= '0' && c <= '9') {
|
||||
c = chars[++i];
|
||||
}
|
||||
} else {
|
||||
return JsonToken.STRING;
|
||||
}
|
||||
|
||||
if (c == '.') {
|
||||
c = chars[++i];
|
||||
while (c >= '0' && c <= '9') {
|
||||
c = chars[++i];
|
||||
}
|
||||
}
|
||||
|
||||
if (c == 'e' || c == 'E') {
|
||||
c = chars[++i];
|
||||
if (c == '+' || c == '-') {
|
||||
c = chars[++i];
|
||||
}
|
||||
if (c >= '0' && c <= '9') {
|
||||
c = chars[++i];
|
||||
while (c >= '0' && c <= '9') {
|
||||
c = chars[++i];
|
||||
}
|
||||
} else {
|
||||
return JsonToken.STRING;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == offset + length) {
|
||||
return JsonToken.NUMBER;
|
||||
} else {
|
||||
return JsonToken.STRING;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1167,4 +1313,23 @@ public class JsonReader implements Closeable {
|
||||
snippet.append(buffer, pos, afterPos);
|
||||
return snippet;
|
||||
}
|
||||
|
||||
static {
|
||||
JsonReaderInternalAccess.INSTANCE = new JsonReaderInternalAccess() {
|
||||
@Override public void promoteNameToValue(JsonReader reader) throws IOException {
|
||||
if (reader instanceof JsonTreeReader) {
|
||||
((JsonTreeReader)reader).promoteNameToValue();
|
||||
return;
|
||||
}
|
||||
reader.peek();
|
||||
if (reader.token != JsonToken.NAME) {
|
||||
throw new IllegalStateException("Expected a name but was " + reader.peek() + " "
|
||||
+ " at line " + reader.getLineNumber() + " column " + reader.getColumnNumber());
|
||||
}
|
||||
reader.value = reader.name;
|
||||
reader.name = null;
|
||||
reader.token = JsonToken.STRING;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonScope;
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Writes a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
|
||||
* encoded value to a stream, one token at a time. The stream includes both
|
||||
|
@ -18,6 +18,8 @@ package com.massivecraft.mcore2.lib.gson.stream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.massivecraft.mcore2.lib.gson.stream.JsonReader;
|
||||
|
||||
/**
|
||||
* Thrown when a reader encounters malformed JSON. Some syntax errors can be
|
||||
* ignored by calling {@link JsonReader#setLenient(boolean)}.
|
||||
|
@ -22,11 +22,11 @@ public class DiscUtil
|
||||
String line;
|
||||
while ((line = in.readLine()) != null)
|
||||
{
|
||||
ret += line;
|
||||
ret += line+"\n";
|
||||
}
|
||||
|
||||
in.close();
|
||||
return ret;
|
||||
return ret.substring(0, ret.length()-1);
|
||||
}
|
||||
|
||||
public static boolean writeCatch(File file, String content)
|
||||
|
@ -198,9 +198,9 @@ public class Txt
|
||||
else return string + repeat(string, times-1);
|
||||
}
|
||||
|
||||
public static String implode(final List<? extends Object> list, final String glue)
|
||||
public static String implode(final Collection<? extends Object> coll, final String glue)
|
||||
{
|
||||
return implode(list.toArray(new Object[0]), glue);
|
||||
return implode(coll.toArray(new Object[0]), glue);
|
||||
}
|
||||
|
||||
public static String implode(final Object[] list, final String glue)
|
||||
|
Loading…
Reference in New Issue
Block a user