New bukkit command integration and latest mcore version.

This commit is contained in:
Olof Larsson 2012-03-30 19:27:57 +02:00
parent cb5f71f2c8
commit 6536631e6d
93 changed files with 2593 additions and 3535 deletions

View File

@ -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.

View File

@ -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);
}
}
}

View File

@ -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
// -------------------------------------------- //

View 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;
}
}

View File

@ -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();
}
}

View File

@ -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()
{

View 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);
}
}

View File

@ -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());
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View 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();
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}

View File

@ -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));
}
};
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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)}

View File

@ -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
*

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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) {

View File

@ -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.
*

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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
*

View File

@ -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;

View File

@ -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.

View File

@ -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);
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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);
}

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -42,10 +42,4 @@ public final class $Gson$Preconditions {
throw new IllegalArgumentException();
}
}
public static void checkState(boolean condition) {
if (!condition) {
throw new IllegalStateException();
}
}
}

View File

@ -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.

View File

@ -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() {

View 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;
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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.
*

View File

@ -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();
}
}

View File

@ -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.
*

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -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));
}
};
}
}

View File

@ -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()));
}
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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 {
}
};
}
}

View File

@ -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;

View File

@ -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;
}
};
}
}

View File

@ -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

View File

@ -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)}.

View File

@ -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)

View File

@ -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)