增加启动xtcp frpc功能

This commit is contained in:
Administrator
2023-01-01 16:20:40 +08:00
parent 1af088a29d
commit 62b22410a3
90 changed files with 11649 additions and 11459 deletions
+32 -53
View File
@@ -1,86 +1,65 @@
{ {
"name" : "KNECloud", "name" : "KNECloud",
"services" : [ { "services" : [ {
"name" : "KNE官网", "name" : "KNE官网",
"protocol" : "HTTP", "protocol" : "HTTP",
"localaddress" : "127.0.0.1:8081" "localaddress" : "127.0.0.1:8081"
}, { }, {
"name" : "KNE云盘", "name" : "KNE云盘",
"protocol" : "HTTP", "protocol" : "HTTP",
"localaddress" : "127.0.0.1:5212" "localaddress" : "127.0.0.1:5212"
}, { }, {
"name" : "服务器远程桌面", "name" : "服务器远程桌面",
"protocol" : "RDP", "protocol" : "RDP",
"localaddress" : "127.0.0.1:3389" "localaddress" : "127.0.0.1:3389"
} ], } ],
"tunnels" : [ { "tunnels" : [ {
"name" : "Openfrp-直连线路", "name" : "Openfrp-直连线路",
"remoteaddress" : "127.0.0.1:4566" "remoteaddress" : "127.0.0.1:4566",
}, { "frpc":[ "[common]",
"name" : "Openfrp-直连线路", "server_addr = 180.76.147.250",
"remoteaddress" : "127.0.0.1:4566" "server_port = 8120",
"tcp_mux = true",
"protocol = tcp",
"dns_server = 223.5.5.5",
"user = bb28264e0abf3bcbec3a2180c5a279b8",
"token = I2KMo1HvRxuvurv2",
"[ts1xx]",
"type = xtcp",
"role = visitor",
"server_name = zl1",
"bind_addr = 127.0.0.1",
"bind_port = 4566",
"sk = knecloud"]
},{ },{
"name" : "NULL-宿迁联通", "name" : "NULL-宿迁联通",
"remoteaddress" : "153.36.240.12:65529" "remoteaddress" : "153.36.240.12:65529"
}, { }, {
"name" : "Openfrp-韩国春川-1", "name" : "Openfrp-北京多线-3",
"remoteaddress" : "kr-nc-bgp-1.openfrp.top:65529"
}, {
"name" : "Openfrp-北京多线-3",
"remoteaddress" : "cn-bj-bgp-3.openfrp.top:65529" "remoteaddress" : "cn-bj-bgp-3.openfrp.top:65529"
}, { }, {
"name" : "Openfrp-北京多线-7", "name" : "Openfrp-北京多线-7",
"remoteaddress" : "180.76.147.250:65529" "remoteaddress" : "180.76.147.250:65529"
}, { }, {
"name" : "Openfrp-美国-8「BGP」", "name" : "Sakurafrp-安徽电信-1",
"remoteaddress" : "us-los-bgp-8.openfrp.top:65529"
}, {
"name" : "Sakurafrp-安徽电信-1",
"remoteaddress" : "cn-ah-dx-1.natfrp.cloud:65529" "remoteaddress" : "cn-ah-dx-1.natfrp.cloud:65529"
}, { }, {
"name" : "Sakurafrp-十堰电信-1", "name" : "Sakurafrp-南宁电信-1",
"remoteaddress" : "cn-sy-dx-1.natfrp.cloud:65529" "remoteaddress" : "cn-nn-dx-1.natfrp.cloud:65529"
}, { }, {
"name" : "Sakurafrp-武汉电信-1", "name" : "Sakurafrp-武汉电信-1",
"remoteaddress" : "cn-wh-dx-1.natfrp.cloud:65529" "remoteaddress" : "cn-wh-dx-1.natfrp.cloud:65529"
}, { }, {
"name" : "Sakurafrp-枣庄BGP-10", "name" : "Sakurafrp-枣庄BGP-10",
"remoteaddress" : "cn-zz-bgp-10.natfrp.cloud:23330" "remoteaddress" : "cn-zz-bgp-10.natfrp.cloud:23330"
}, { }, {
"name" : "Sakurafrp-枣庄BGP-7", "name" : "Sakurafrp-枣庄BGP-7",
"remoteaddress" : "cn-zz-bgp-7.natfrp.cloud:33336" "remoteaddress" : "cn-zz-bgp-7.natfrp.cloud:33336"
}, { }, {
"name" : "HYHBX-深圳阿里-1", "name" : "HYHBX-深圳阿里-1",
"remoteaddress" : "119.23.238.91:12413" "remoteaddress" : "119.23.238.91:12413"
}, { }, {
"name" : "HYHBX-上海腾讯-2", "name" : "HYHBX-上海腾讯-2",
"remoteaddress" : "43.143.109.64:49965" "remoteaddress" : "43.143.109.64:49965"
}, {
"name" : "XYZ-韩国首尔",
"remoteaddress" : "frp.104300.xyz:49965"
}, {
"name" : "aFrps-美国洛杉矶",
"remoteaddress" : "la.afrps.cn:49966"
}, {
"name" : "aFrps-新加坡",
"remoteaddress" : "sg.afrps.cn:49966"
}, {
"name" : "aFrps-美国芝加哥",
"remoteaddress" : "ch.afrps.cn:49966"
}, {
"name" : "aFrps-美国圣何塞",
"remoteaddress" : "sj.afrps.cn:49966"
} , {
"name" : "Freefrp-韩国首尔-0",
"remoteaddress" : "frp.freefrp.net:49965"
}, {
"name" : "Freefrp-韩国首尔-1",
"remoteaddress" : "frp1.freefrp.net:49965"
}, {
"name" : "Freefrp-韩国首尔-2",
"remoteaddress" : "frp2.freefrp.net:49965"
}, {
"name" : "Freefrp-韩国首尔-4",
"remoteaddress" : "frp4.freefrp.net:49965"
}] }]
} }
-86
View File
@@ -1,86 +0,0 @@
{
"name" : "KNECloud",
"services" : [ {
"name" : "KNE官网",
"protocol" : "HTTP",
"localaddress" : "127.0.0.1:8081"
}, {
"name" : "KNE云盘",
"protocol" : "HTTP",
"localaddress" : "127.0.0.1:5212"
}, {
"name" : "服务器远程桌面",
"protocol" : "RDP",
"localaddress" : "127.0.0.1:3389"
} ],
"tunnels" : [ {
"name" : "Openfrp-直连线路",
"remoteaddress" : "127.0.0.1:4566"
}, {
"name" : "Openfrp-直连线路",
"remoteaddress" : "127.0.0.1:4566"
},{
"name" : "NULL-宿迁联通",
"remoteaddress" : "153.36.240.12:65529"
}, {
"name" : "Openfrp-韩国春川-1",
"remoteaddress" : "kr-nc-bgp-1.openfrp.top:65529"
}, {
"name" : "Openfrp-北京多线-3",
"remoteaddress" : "cn-bj-bgp-3.openfrp.top:65529"
}, {
"name" : "Openfrp-北京多线-7",
"remoteaddress" : "180.76.147.250:65529"
}, {
"name" : "Openfrp-美国-8「BGP」",
"remoteaddress" : "us-los-bgp-8.openfrp.top:65529"
}, {
"name" : "Sakurafrp-安徽电信-1",
"remoteaddress" : "cn-ah-dx-1.natfrp.cloud:65529"
}, {
"name" : "Sakurafrp-十堰电信-1",
"remoteaddress" : "cn-sy-dx-1.natfrp.cloud:65529"
}, {
"name" : "Sakurafrp-武汉电信-1",
"remoteaddress" : "cn-wh-dx-1.natfrp.cloud:65529"
}, {
"name" : "Sakurafrp-枣庄BGP-10",
"remoteaddress" : "cn-zz-bgp-10.natfrp.cloud:23330"
}, {
"name" : "Sakurafrp-枣庄BGP-7",
"remoteaddress" : "cn-zz-bgp-7.natfrp.cloud:33336"
}, {
"name" : "HYHBX-深圳阿里-1",
"remoteaddress" : "119.23.238.91:12413"
}, {
"name" : "HYHBX-上海腾讯-2",
"remoteaddress" : "43.143.109.64:49965"
}, {
"name" : "XYZ-韩国首尔",
"remoteaddress" : "frp.104300.xyz:49965"
}, {
"name" : "aFrps-美国洛杉矶",
"remoteaddress" : "la.afrps.cn:49966"
}, {
"name" : "aFrps-新加坡",
"remoteaddress" : "sg.afrps.cn:49966"
}, {
"name" : "aFrps-美国芝加哥",
"remoteaddress" : "ch.afrps.cn:49966"
}, {
"name" : "aFrps-美国圣何塞",
"remoteaddress" : "sj.afrps.cn:49966"
} , {
"name" : "Freefrp-韩国首尔-0",
"remoteaddress" : "frp.freefrp.net:49965"
}, {
"name" : "Freefrp-韩国首尔-1",
"remoteaddress" : "frp1.freefrp.net:49965"
}, {
"name" : "Freefrp-韩国首尔-2",
"remoteaddress" : "frp2.freefrp.net:49965"
}, {
"name" : "Freefrp-韩国首尔-4",
"remoteaddress" : "frp4.freefrp.net:49965"
}]
}
+29
View File
@@ -0,0 +1,29 @@
{
"name" : "KNECloud",
"services" : [ {
"name" : "KNE官网",
"protocol" : "HTTP",
"localaddress" : "127.0.0.1:8081"
}, {
"name" : "KNE云盘",
"protocol" : "HTTP",
"localaddress" : "127.0.0.1:5212"
}, {
"name" : "服务器远程桌面",
"protocol" : "RDP",
"localaddress" : "127.0.0.1:3389"
} ],
"tunnels" : [ {
"name" : "Openfrp-韩国春川-1",
"remoteaddress" : "kr-nc-bgp-1.openfrp.top:65529"
}, {
"name" : "Openfrp-北京多线-3",
"remoteaddress" : "cn-bj-bgp-3.openfrp.top:65529"
}, {
"name" : "Openfrp-北京多线-7",
"remoteaddress" : "180.76.147.250:65529"
}, {
"name" : "Openfrp-美国-8「BGP」",
"remoteaddress" : "us-los-bgp-8.openfrp.top:65529"
}]
}
+119 -119
View File
@@ -1,119 +1,119 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
* This type adapter supports three subclasses of date: Date, Timestamp, and * This type adapter supports three subclasses of date: Date, Timestamp, and
* java.sql.Date. * java.sql.Date.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> { final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
// TODO: migrate to streaming adapter // TODO: migrate to streaming adapter
private final DateFormat enUsFormat; private final DateFormat enUsFormat;
private final DateFormat localFormat; private final DateFormat localFormat;
private final DateFormat iso8601Format; private final DateFormat iso8601Format;
DefaultDateTypeAdapter() { DefaultDateTypeAdapter() {
this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US), this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)); DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
} }
DefaultDateTypeAdapter(String datePattern) { DefaultDateTypeAdapter(String datePattern) {
this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern)); this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
} }
DefaultDateTypeAdapter(int style) { DefaultDateTypeAdapter(int style) {
this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style)); this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
} }
public DefaultDateTypeAdapter(int dateStyle, int timeStyle) { public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US), this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
DateFormat.getDateTimeInstance(dateStyle, timeStyle)); DateFormat.getDateTimeInstance(dateStyle, timeStyle));
} }
DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) { DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
this.enUsFormat = enUsFormat; this.enUsFormat = enUsFormat;
this.localFormat = localFormat; this.localFormat = localFormat;
this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
} }
// These methods need to be synchronized since JDK DateFormat classes are not thread-safe // These methods need to be synchronized since JDK DateFormat classes are not thread-safe
// See issue 162 // See issue 162
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
synchronized (localFormat) { synchronized (localFormat) {
String dateFormatAsString = enUsFormat.format(src); String dateFormatAsString = enUsFormat.format(src);
return new JsonPrimitive(dateFormatAsString); return new JsonPrimitive(dateFormatAsString);
} }
} }
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
if (!(json instanceof JsonPrimitive)) { if (!(json instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value"); throw new JsonParseException("The date should be a string value");
} }
Date date = deserializeToDate(json); Date date = deserializeToDate(json);
if (typeOfT == Date.class) { if (typeOfT == Date.class) {
return date; return date;
} else if (typeOfT == Timestamp.class) { } else if (typeOfT == Timestamp.class) {
return new Timestamp(date.getTime()); return new Timestamp(date.getTime());
} else if (typeOfT == java.sql.Date.class) { } else if (typeOfT == java.sql.Date.class) {
return new java.sql.Date(date.getTime()); return new java.sql.Date(date.getTime());
} else { } else {
throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT); throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT);
} }
} }
private Date deserializeToDate(JsonElement json) { private Date deserializeToDate(JsonElement json) {
synchronized (localFormat) { synchronized (localFormat) {
try { try {
return localFormat.parse(json.getAsString()); return localFormat.parse(json.getAsString());
} catch (ParseException ignored) { } catch (ParseException ignored) {
} }
try { try {
return enUsFormat.parse(json.getAsString()); return enUsFormat.parse(json.getAsString());
} catch (ParseException ignored) { } catch (ParseException ignored) {
} }
try { try {
return iso8601Format.parse(json.getAsString()); return iso8601Format.parse(json.getAsString());
} catch (ParseException e) { } catch (ParseException e) {
throw new JsonSyntaxException(json.getAsString(), e); throw new JsonSyntaxException(json.getAsString(), e);
} }
} }
} }
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(DefaultDateTypeAdapter.class.getSimpleName()); sb.append(DefaultDateTypeAdapter.class.getSimpleName());
sb.append('(').append(localFormat.getClass().getSimpleName()).append(')'); sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
return sb.toString(); return sb.toString();
} }
} }
+109 -109
View File
@@ -1,109 +1,109 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
/** /**
* A strategy (or policy) definition that is used to decide whether or not a field or top-level * 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, * class should be serialized or deserialized as part of the JSON output/input. For serialization,
* if the {@link #shouldSkipClass(Class)} method returns false then that class or field type * if the {@link #shouldSkipClass(Class)} method returns false then that class or field type
* will not be part of the JSON output. For deserialization, if {@link #shouldSkipClass(Class)} * will not be part of the JSON output. For deserialization, if {@link #shouldSkipClass(Class)}
* returns false, then it will not be set as part of the Java object structure. * returns false, then it will not be set as part of the Java object structure.
* *
* <p>The following are a few examples that shows how you can use this exclusion mechanism. * <p>The following are a few examples that shows how you can use this exclusion mechanism.
* *
* <p><strong>Exclude fields and objects based on a particular class type:</strong> * <p><strong>Exclude fields and objects based on a particular class type:</strong>
* <pre class="code"> * <pre class="code">
* private static class SpecificClassExclusionStrategy implements ExclusionStrategy { * private static class SpecificClassExclusionStrategy implements ExclusionStrategy {
* private final Class&lt;?&gt; excludedThisClass; * private final Class&lt;?&gt; excludedThisClass;
* *
* public SpecificClassExclusionStrategy(Class&lt;?&gt; excludedThisClass) { * public SpecificClassExclusionStrategy(Class&lt;?&gt; excludedThisClass) {
* this.excludedThisClass = excludedThisClass; * this.excludedThisClass = excludedThisClass;
* } * }
* *
* public boolean shouldSkipClass(Class&lt;?&gt; clazz) { * public boolean shouldSkipClass(Class&lt;?&gt; clazz) {
* return excludedThisClass.equals(clazz); * return excludedThisClass.equals(clazz);
* } * }
* *
* public boolean shouldSkipField(FieldAttributes f) { * public boolean shouldSkipField(FieldAttributes f) {
* return excludedThisClass.equals(f.getDeclaredClass()); * return excludedThisClass.equals(f.getDeclaredClass());
* } * }
* } * }
* </pre> * </pre>
* *
* <p><strong>Excludes fields and objects based on a particular annotation:</strong> * <p><strong>Excludes fields and objects based on a particular annotation:</strong>
* <pre class="code"> * <pre class="code">
* public &#64interface FooAnnotation { * public &#64interface FooAnnotation {
* // some implementation here * // some implementation here
* } * }
* *
* // Excludes any field (or class) that is tagged with an "&#64FooAnnotation" * // Excludes any field (or class) that is tagged with an "&#64FooAnnotation"
* private static class FooAnnotationExclusionStrategy implements ExclusionStrategy { * private static class FooAnnotationExclusionStrategy implements ExclusionStrategy {
* public boolean shouldSkipClass(Class&lt;?&gt; clazz) { * public boolean shouldSkipClass(Class&lt;?&gt; clazz) {
* return clazz.getAnnotation(FooAnnotation.class) != null; * return clazz.getAnnotation(FooAnnotation.class) != null;
* } * }
* *
* public boolean shouldSkipField(FieldAttributes f) { * public boolean shouldSkipField(FieldAttributes f) {
* return f.getAnnotation(FooAnnotation.class) != null; * return f.getAnnotation(FooAnnotation.class) != null;
* } * }
* } * }
* </pre> * </pre>
* *
* <p>Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then * <p>Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then
* the {@code GsonBuilder} is required. The following is an example of how you can use the * the {@code GsonBuilder} is required. The following is an example of how you can use the
* {@code GsonBuilder} to configure Gson to use one of the above sample: * {@code GsonBuilder} to configure Gson to use one of the above sample:
* <pre class="code"> * <pre class="code">
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class); * ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
* Gson gson = new GsonBuilder() * Gson gson = new GsonBuilder()
* .setExclusionStrategies(excludeStrings) * .setExclusionStrategies(excludeStrings)
* .create(); * .create();
* </pre> * </pre>
* *
* <p>For certain model classes, you may only want to serialize a field, but exclude it for * <p>For certain model classes, you may only want to serialize a field, but exclude it for
* deserialization. To do that, you can write an {@code ExclusionStrategy} as per normal; * deserialization. To do that, you can write an {@code ExclusionStrategy} as per normal;
* however, you would register it with the * however, you would register it with the
* {@link GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)} method. * {@link GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)} method.
* For example: * For example:
* <pre class="code"> * <pre class="code">
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class); * ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
* Gson gson = new GsonBuilder() * Gson gson = new GsonBuilder()
* .addDeserializationExclusionStrategy(excludeStrings) * .addDeserializationExclusionStrategy(excludeStrings)
* .create(); * .create();
* </pre> * </pre>
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* *
* @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...) * @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
* @see GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy) * @see GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)
* @see GsonBuilder#addSerializationExclusionStrategy(ExclusionStrategy) * @see GsonBuilder#addSerializationExclusionStrategy(ExclusionStrategy)
* *
* @since 1.4 * @since 1.4
*/ */
public interface ExclusionStrategy { public interface ExclusionStrategy {
/** /**
* @param f the field object that is under test * @param f the field object that is under test
* @return true if the field should be ignored; otherwise false * @return true if the field should be ignored; otherwise false
*/ */
public boolean shouldSkipField(FieldAttributes f); public boolean shouldSkipField(FieldAttributes f);
/** /**
* @param clazz the class object that is under test * @param clazz the class object that is under test
* @return true if the class should be ignored; otherwise false * @return true if the class should be ignored; otherwise false
*/ */
public boolean shouldSkipClass(Class<?> clazz); public boolean shouldSkipClass(Class<?> clazz);
} }
+157 -157
View File
@@ -1,157 +1,157 @@
/* /*
* Copyright (C) 2009 Google Inc. * Copyright (C) 2009 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.$Gson$Preconditions;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
/** /**
* A data object that stores attributes of a field. * A data object that stores attributes of a field.
* *
* <p>This class is immutable; therefore, it can be safely shared across threads. * <p>This class is immutable; therefore, it can be safely shared across threads.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* *
* @since 1.4 * @since 1.4
*/ */
public final class FieldAttributes { public final class FieldAttributes {
private final Field field; private final Field field;
/** /**
* Constructs a Field Attributes object from the {@code f}. * Constructs a Field Attributes object from the {@code f}.
* *
* @param f the field to pull attributes from * @param f the field to pull attributes from
*/ */
public FieldAttributes(Field f) { public FieldAttributes(Field f) {
$Gson$Preconditions.checkNotNull(f); $Gson$Preconditions.checkNotNull(f);
this.field = f; this.field = f;
} }
/** /**
* @return the declaring class that contains this field * @return the declaring class that contains this field
*/ */
public Class<?> getDeclaringClass() { public Class<?> getDeclaringClass() {
return field.getDeclaringClass(); return field.getDeclaringClass();
} }
/** /**
* @return the name of the field * @return the name of the field
*/ */
public String getName() { public String getName() {
return field.getName(); return field.getName();
} }
/** /**
* <p>For example, assume the following class definition: * <p>For example, assume the following class definition:
* <pre class="code"> * <pre class="code">
* public class Foo { * public class Foo {
* private String bar; * private String bar;
* private List&lt;String&gt; red; * private List&lt;String&gt; red;
* } * }
* *
* Type listParmeterizedType = new TypeToken&lt;List&lt;String&gt;&gt;() {}.getType(); * Type listParmeterizedType = new TypeToken&lt;List&lt;String&gt;&gt;() {}.getType();
* </pre> * </pre>
* *
* <p>This method would return {@code String.class} for the {@code bar} field and * <p>This method would return {@code String.class} for the {@code bar} field and
* {@code listParameterizedType} for the {@code red} field. * {@code listParameterizedType} for the {@code red} field.
* *
* @return the specific type declared for this field * @return the specific type declared for this field
*/ */
public Type getDeclaredType() { public Type getDeclaredType() {
return field.getGenericType(); return field.getGenericType();
} }
/** /**
* Returns the {@code Class} object that was declared for this field. * Returns the {@code Class} object that was declared for this field.
* *
* <p>For example, assume the following class definition: * <p>For example, assume the following class definition:
* <pre class="code"> * <pre class="code">
* public class Foo { * public class Foo {
* private String bar; * private String bar;
* private List&lt;String&gt; red; * private List&lt;String&gt; red;
* } * }
* </pre> * </pre>
* *
* <p>This method would return {@code String.class} for the {@code bar} field and * <p>This method would return {@code String.class} for the {@code bar} field and
* {@code List.class} for the {@code red} field. * {@code List.class} for the {@code red} field.
* *
* @return the specific class object that was declared for the field * @return the specific class object that was declared for the field
*/ */
public Class<?> getDeclaredClass() { public Class<?> getDeclaredClass() {
return field.getType(); return field.getType();
} }
/** /**
* Return the {@code T} annotation object from this field if it exist; otherwise returns * Return the {@code T} annotation object from this field if it exist; otherwise returns
* {@code null}. * {@code null}.
* *
* @param annotation the class of the annotation that will be retrieved * @param annotation the class of the annotation that will be retrieved
* @return the annotation instance if it is bound to the field; otherwise {@code null} * @return the annotation instance if it is bound to the field; otherwise {@code null}
*/ */
public <T extends Annotation> T getAnnotation(Class<T> annotation) { public <T extends Annotation> T getAnnotation(Class<T> annotation) {
return field.getAnnotation(annotation); return field.getAnnotation(annotation);
} }
/** /**
* Return the annotations that are present on this field. * Return the annotations that are present on this field.
* *
* @return an array of all the annotations set on the field * @return an array of all the annotations set on the field
* @since 1.4 * @since 1.4
*/ */
public Collection<Annotation> getAnnotations() { public Collection<Annotation> getAnnotations() {
return Arrays.asList(field.getAnnotations()); return Arrays.asList(field.getAnnotations());
} }
/** /**
* Returns {@code true} if the field is defined with the {@code modifier}. * Returns {@code true} if the field is defined with the {@code modifier}.
* *
* <p>This method is meant to be called as: * <p>This method is meant to be called as:
* <pre class="code"> * <pre class="code">
* boolean hasPublicModifier = fieldAttribute.hasModifier(java.lang.reflect.Modifier.PUBLIC); * boolean hasPublicModifier = fieldAttribute.hasModifier(java.lang.reflect.Modifier.PUBLIC);
* </pre> * </pre>
* *
* @see java.lang.reflect.Modifier * @see java.lang.reflect.Modifier
*/ */
public boolean hasModifier(int modifier) { public boolean hasModifier(int modifier) {
return (field.getModifiers() & modifier) != 0; return (field.getModifiers() & modifier) != 0;
} }
/** /**
* This is exposed internally only for the removing synthetic fields from the JSON output. * This is exposed internally only for the removing synthetic fields from the JSON output.
* *
* @return true if the field is synthetic; otherwise false * @return true if the field is synthetic; otherwise false
* @throws IllegalAccessException * @throws IllegalAccessException
* @throws IllegalArgumentException * @throws IllegalArgumentException
*/ */
Object get(Object instance) throws IllegalAccessException { Object get(Object instance) throws IllegalAccessException {
return field.get(instance); return field.get(instance);
} }
/** /**
* This is exposed internally only for the removing synthetic fields from the JSON output. * This is exposed internally only for the removing synthetic fields from the JSON output.
* *
* @return true if the field is synthetic; otherwise false * @return true if the field is synthetic; otherwise false
*/ */
boolean isSynthetic() { boolean isSynthetic() {
return field.isSynthetic(); return field.isSynthetic();
} }
} }
+168 -168
View File
@@ -1,168 +1,168 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Field; import java.lang.reflect.Field;
/** /**
* An enumeration that defines a few standard naming conventions for JSON field names. * An enumeration that defines a few standard naming conventions for JSON field names.
* This enumeration should be used in conjunction with {@link com.google.gson.GsonBuilder} * This enumeration should be used in conjunction with {@link com.google.gson.GsonBuilder}
* to configure a {@link com.google.gson.Gson} instance to properly translate Java field * to configure a {@link com.google.gson.Gson} instance to properly translate Java field
* names into the desired JSON field names. * names into the desired JSON field names.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public enum FieldNamingPolicy implements FieldNamingStrategy { public enum FieldNamingPolicy implements FieldNamingStrategy {
/** /**
* Using this naming policy with Gson will ensure that the field name is * Using this naming policy with Gson will ensure that the field name is
* unchanged. * unchanged.
*/ */
IDENTITY() { IDENTITY() {
public String translateName(Field f) { public String translateName(Field f) {
return f.getName(); return f.getName();
} }
}, },
/** /**
* Using this naming policy with Gson will ensure that the first "letter" of the Java * 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. * field name is capitalized when serialized to its JSON form.
* *
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p> * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
* <ul> * <ul>
* <li>someFieldName ---> SomeFieldName</li> * <li>someFieldName ---> SomeFieldName</li>
* <li>_someFieldName ---> _SomeFieldName</li> * <li>_someFieldName ---> _SomeFieldName</li>
* </ul> * </ul>
*/ */
UPPER_CAMEL_CASE() { UPPER_CAMEL_CASE() {
public String translateName(Field f) { public String translateName(Field f) {
return upperCaseFirstLetter(f.getName()); return upperCaseFirstLetter(f.getName());
} }
}, },
/** /**
* Using this naming policy with Gson will ensure that the first "letter" of the Java * Using this naming policy with Gson will ensure that the first "letter" of the Java
* field name is capitalized when serialized to its JSON form and the words will be * field name is capitalized when serialized to its JSON form and the words will be
* separated by a space. * separated by a space.
* *
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p> * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
* <ul> * <ul>
* <li>someFieldName ---> Some Field Name</li> * <li>someFieldName ---> Some Field Name</li>
* <li>_someFieldName ---> _Some Field Name</li> * <li>_someFieldName ---> _Some Field Name</li>
* </ul> * </ul>
* *
* @since 1.4 * @since 1.4
*/ */
UPPER_CAMEL_CASE_WITH_SPACES() { UPPER_CAMEL_CASE_WITH_SPACES() {
public String translateName(Field f) { public String translateName(Field f) {
return upperCaseFirstLetter(separateCamelCase(f.getName(), " ")); return upperCaseFirstLetter(separateCamelCase(f.getName(), " "));
} }
}, },
/** /**
* Using this naming policy with Gson will modify the Java Field name from its camel cased * Using this naming policy with Gson will modify the Java Field name from its camel cased
* form to a lower case field name where each word is separated by an underscore (_). * form to a lower case field name where each word is separated by an underscore (_).
* *
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p> * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
* <ul> * <ul>
* <li>someFieldName ---> some_field_name</li> * <li>someFieldName ---> some_field_name</li>
* <li>_someFieldName ---> _some_field_name</li> * <li>_someFieldName ---> _some_field_name</li>
* <li>aStringField ---> a_string_field</li> * <li>aStringField ---> a_string_field</li>
* <li>aURL ---> a_u_r_l</li> * <li>aURL ---> a_u_r_l</li>
* </ul> * </ul>
*/ */
LOWER_CASE_WITH_UNDERSCORES() { LOWER_CASE_WITH_UNDERSCORES() {
public String translateName(Field f) { public String translateName(Field f) {
return separateCamelCase(f.getName(), "_").toLowerCase(); return separateCamelCase(f.getName(), "_").toLowerCase();
} }
}, },
/** /**
* Using this naming policy with Gson will modify the Java Field name from its camel cased * Using this naming policy with Gson will modify the Java Field name from its camel cased
* form to a lower case field name where each word is separated by a dash (-). * form to a lower case field name where each word is separated by a dash (-).
* *
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p> * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
* <ul> * <ul>
* <li>someFieldName ---> some-field-name</li> * <li>someFieldName ---> some-field-name</li>
* <li>_someFieldName ---> _some-field-name</li> * <li>_someFieldName ---> _some-field-name</li>
* <li>aStringField ---> a-string-field</li> * <li>aStringField ---> a-string-field</li>
* <li>aURL ---> a-u-r-l</li> * <li>aURL ---> a-u-r-l</li>
* </ul> * </ul>
* Using dashes in JavaScript is not recommended since dash is also used for a minus sign in * Using dashes in JavaScript is not recommended since dash is also used for a minus sign in
* expressions. This requires that a field named with dashes is always accessed as a quoted * expressions. This requires that a field named with dashes is always accessed as a quoted
* property like {@code myobject['my-field']}. Accessing it as an object field * property like {@code myobject['my-field']}. Accessing it as an object field
* {@code myobject.my-field} will result in an unintended javascript expression. * {@code myobject.my-field} will result in an unintended javascript expression.
* @since 1.4 * @since 1.4
*/ */
LOWER_CASE_WITH_DASHES() { LOWER_CASE_WITH_DASHES() {
public String translateName(Field f) { public String translateName(Field f) {
return separateCamelCase(f.getName(), "-").toLowerCase(); return separateCamelCase(f.getName(), "-").toLowerCase();
} }
}; };
/** /**
* Converts the field name that uses camel-case define word separation into * Converts the field name that uses camel-case define word separation into
* separate words that are separated by the provided {@code separatorString}. * separate words that are separated by the provided {@code separatorString}.
*/ */
private static String separateCamelCase(String name, String separator) { private static String separateCamelCase(String name, String separator) {
StringBuilder translation = new StringBuilder(); StringBuilder translation = new StringBuilder();
for (int i = 0; i < name.length(); i++) { for (int i = 0; i < name.length(); i++) {
char character = name.charAt(i); char character = name.charAt(i);
if (Character.isUpperCase(character) && translation.length() != 0) { if (Character.isUpperCase(character) && translation.length() != 0) {
translation.append(separator); translation.append(separator);
} }
translation.append(character); translation.append(character);
} }
return translation.toString(); return translation.toString();
} }
/** /**
* Ensures the JSON field names begins with an upper case letter. * Ensures the JSON field names begins with an upper case letter.
*/ */
private static String upperCaseFirstLetter(String name) { private static String upperCaseFirstLetter(String name) {
StringBuilder fieldNameBuilder = new StringBuilder(); StringBuilder fieldNameBuilder = new StringBuilder();
int index = 0; int index = 0;
char firstCharacter = name.charAt(index); char firstCharacter = name.charAt(index);
while (index < name.length() - 1) { while (index < name.length() - 1) {
if (Character.isLetter(firstCharacter)) { if (Character.isLetter(firstCharacter)) {
break; break;
} }
fieldNameBuilder.append(firstCharacter); fieldNameBuilder.append(firstCharacter);
firstCharacter = name.charAt(++index); firstCharacter = name.charAt(++index);
} }
if (index == name.length()) { if (index == name.length()) {
return fieldNameBuilder.toString(); return fieldNameBuilder.toString();
} }
if (!Character.isUpperCase(firstCharacter)) { if (!Character.isUpperCase(firstCharacter)) {
String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), name, ++index); String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), name, ++index);
return fieldNameBuilder.append(modifiedTarget).toString(); return fieldNameBuilder.append(modifiedTarget).toString();
} else { } else {
return name; return name;
} }
} }
private static String modifyString(char firstCharacter, String srcString, int indexOfSubstring) { private static String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
return (indexOfSubstring < srcString.length()) return (indexOfSubstring < srcString.length())
? firstCharacter + srcString.substring(indexOfSubstring) ? firstCharacter + srcString.substring(indexOfSubstring)
: String.valueOf(firstCharacter); : String.valueOf(firstCharacter);
} }
} }
+40 -40
View File
@@ -1,40 +1,40 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Field; import java.lang.reflect.Field;
/** /**
* A mechanism for providing custom field naming in Gson. This allows the client code to translate * 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 * 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. * declaration rules. For example, Java does not support "-" characters in a field name.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* @since 1.3 * @since 1.3
*/ */
public interface FieldNamingStrategy { public interface FieldNamingStrategy {
/** /**
* Translates the field name into its JSON field name representation. * Translates the field name into its JSON field name representation.
* *
* @param f the field object that we are translating * @param f the field object that we are translating
* @return the translated field name. * @return the translated field name.
* @since 1.3 * @since 1.3
*/ */
public String translateName(Field f); public String translateName(Field f);
} }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+92 -92
View File
@@ -1,92 +1,92 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* This interface is implemented to create instances of a class that does not define a no-args * 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 * constructor. If you can modify the class, you should instead add a private, or public
* no-args constructor. However, that is not possible for library classes, such as JDK classes, or * no-args constructor. However, that is not possible for library classes, such as JDK classes, or
* a third-party library that you do not have source-code of. In such cases, you should define an * a third-party library that you do not have source-code of. In such cases, you should define an
* instance creator for the class. Implementations of this interface should be registered with * instance creator for the class. Implementations of this interface should be registered with
* {@link GsonBuilder#registerTypeAdapter(Type, Object)} method before Gson will be able to use * {@link GsonBuilder#registerTypeAdapter(Type, Object)} method before Gson will be able to use
* them. * them.
* <p>Let us look at an example where defining an InstanceCreator might be useful. The * <p>Let us look at an example where defining an InstanceCreator might be useful. The
* {@code Id} class defined below does not have a default no-args constructor.</p> * {@code Id} class defined below does not have a default no-args constructor.</p>
* *
* <pre> * <pre>
* public class Id&lt;T&gt; { * public class Id&lt;T&gt; {
* private final Class&lt;T&gt; clazz; * private final Class&lt;T&gt; clazz;
* private final long value; * private final long value;
* public Id(Class&lt;T&gt; clazz, long value) { * public Id(Class&lt;T&gt; clazz, long value) {
* this.clazz = clazz; * this.clazz = clazz;
* this.value = value; * this.value = value;
* } * }
* } * }
* </pre> * </pre>
* *
* <p>If Gson encounters an object of type {@code Id} during deserialization, it will throw an * <p>If Gson encounters an object of type {@code Id} during deserialization, it will throw an
* exception. The easiest way to solve this problem will be to add a (public or private) no-args * exception. The easiest way to solve this problem will be to add a (public or private) no-args
* constructor as follows:</p> * constructor as follows:</p>
* *
* <pre> * <pre>
* private Id() { * private Id() {
* this(Object.class, 0L); * this(Object.class, 0L);
* } * }
* </pre> * </pre>
* *
* <p>However, let us assume that the developer does not have access to the source-code of the * <p>However, let us assume that the developer does not have access to the source-code of the
* {@code Id} class, or does not want to define a no-args constructor for it. The developer * {@code Id} class, or does not want to define a no-args constructor for it. The developer
* can solve this problem by defining an {@code InstanceCreator} for {@code Id}:</p> * can solve this problem by defining an {@code InstanceCreator} for {@code Id}:</p>
* *
* <pre> * <pre>
* class IdInstanceCreator implements InstanceCreator&lt;Id&gt; { * class IdInstanceCreator implements InstanceCreator&lt;Id&gt; {
* public Id createInstance(Type type) { * public Id createInstance(Type type) {
* return new Id(Object.class, 0L); * return new Id(Object.class, 0L);
* } * }
* } * }
* </pre> * </pre>
* *
* <p>Note that it does not matter what the fields of the created instance contain since Gson will * <p>Note that it does not matter what the fields of the created instance contain since Gson will
* overwrite them with the deserialized values specified in Json. You should also ensure that a * overwrite them with the deserialized values specified in Json. You should also ensure that a
* <i>new</i> object is returned, not a common object since its fields will be overwritten. * <i>new</i> object is returned, not a common object since its fields will be overwritten.
* The developer will need to register {@code IdInstanceCreator} with Gson as follows:</p> * The developer will need to register {@code IdInstanceCreator} with Gson as follows:</p>
* *
* <pre> * <pre>
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create(); * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();
* </pre> * </pre>
* *
* @param <T> the type of object that will be created by this implementation. * @param <T> the type of object that will be created by this implementation.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public interface InstanceCreator<T> { public interface InstanceCreator<T> {
/** /**
* Gson invokes this call-back method during deserialization to create an instance of the * Gson invokes this call-back method during deserialization to create an instance of the
* specified type. The fields of the returned instance are overwritten with the data present * specified type. The fields of the returned instance are overwritten with the data present
* in the Json. Since the prior contents of the object are destroyed and overwritten, do not * in the Json. Since the prior contents of the object are destroyed and overwritten, do not
* return an instance that is useful elsewhere. In particular, do not return a common instance, * return an instance that is useful elsewhere. In particular, do not return a common instance,
* always use {@code new} to create a new instance. * always use {@code new} to create a new instance.
* *
* @param type the parameterized T represented as a {@link Type}. * @param type the parameterized T represented as a {@link Type}.
* @return a default object instance of type T. * @return a default object instance of type T.
*/ */
public T createInstance(Type type); public T createInstance(Type type);
} }
+282 -282
View File
@@ -1,282 +1,282 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
* A class representing an array type in Json. An array is a list of {@link JsonElement}s each of * 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 * which can be of a different type. This is an ordered list, meaning that the order in which
* elements are added is preserved. * elements are added is preserved.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class JsonArray extends JsonElement implements Iterable<JsonElement> { public final class JsonArray extends JsonElement implements Iterable<JsonElement> {
private final List<JsonElement> elements; private final List<JsonElement> elements;
/** /**
* Creates an empty JsonArray. * Creates an empty JsonArray.
*/ */
public JsonArray() { public JsonArray() {
elements = new ArrayList<JsonElement>(); elements = new ArrayList<JsonElement>();
} }
/** /**
* Adds the specified element to self. * Adds the specified element to self.
* *
* @param element the element that needs to be added to the array. * @param element the element that needs to be added to the array.
*/ */
public void add(JsonElement element) { public void add(JsonElement element) {
if (element == null) { if (element == null) {
element = JsonNull.INSTANCE; element = JsonNull.INSTANCE;
} }
elements.add(element); elements.add(element);
} }
/** /**
* Adds all the elements of the specified array to self. * Adds all the elements of the specified array to self.
* *
* @param array the array whose elements need to be added to the array. * @param array the array whose elements need to be added to the array.
*/ */
public void addAll(JsonArray array) { public void addAll(JsonArray array) {
elements.addAll(array.elements); elements.addAll(array.elements);
} }
/** /**
* Returns the number of elements in the array. * Returns the number of elements in the array.
* *
* @return the number of elements in the array. * @return the number of elements in the array.
*/ */
public int size() { public int size() {
return elements.size(); return elements.size();
} }
/** /**
* Returns an iterator to navigate the elemetns of the array. Since the array is an ordered list, * Returns an iterator to navigate the elemetns of the array. Since the array is an ordered list,
* the iterator navigates the elements in the order they were inserted. * the iterator navigates the elements in the order they were inserted.
* *
* @return an iterator to navigate the elements of the array. * @return an iterator to navigate the elements of the array.
*/ */
public Iterator<JsonElement> iterator() { public Iterator<JsonElement> iterator() {
return elements.iterator(); return elements.iterator();
} }
/** /**
* Returns the ith element of the array. * Returns the ith element of the array.
* *
* @param i the index of the element that is being sought. * @param i the index of the element that is being sought.
* @return the element present at the ith index. * @return the element present at the ith index.
* @throws IndexOutOfBoundsException if i is negative or greater than or equal to the * @throws IndexOutOfBoundsException if i is negative or greater than or equal to the
* {@link #size()} of the array. * {@link #size()} of the array.
*/ */
public JsonElement get(int i) { public JsonElement get(int i) {
return elements.get(i); return elements.get(i);
} }
/** /**
* convenience method to get this array as a {@link Number} if it contains a single element. * convenience method to get this array as a {@link Number} if it contains a single element.
* *
* @return get this element as a number if it is single element array. * @return get this element as a number if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid Number. * is not a valid Number.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public Number getAsNumber() { public Number getAsNumber() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsNumber(); return elements.get(0).getAsNumber();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a {@link String} if it contains a single element. * convenience method to get this array as a {@link String} if it contains a single element.
* *
* @return get this element as a String if it is single element array. * @return get this element as a String if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid String. * is not a valid String.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public String getAsString() { public String getAsString() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsString(); return elements.get(0).getAsString();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a double if it contains a single element. * convenience method to get this array as a double if it contains a single element.
* *
* @return get this element as a double if it is single element array. * @return get this element as a double if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid double. * is not a valid double.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public double getAsDouble() { public double getAsDouble() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsDouble(); return elements.get(0).getAsDouble();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a {@link BigDecimal} if it contains a single element. * convenience method to get this array as a {@link BigDecimal} if it contains a single element.
* *
* @return get this element as a {@link BigDecimal} if it is single element array. * @return get this element as a {@link BigDecimal} if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
* @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}. * @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
* @since 1.2 * @since 1.2
*/ */
@Override @Override
public BigDecimal getAsBigDecimal() { public BigDecimal getAsBigDecimal() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsBigDecimal(); return elements.get(0).getAsBigDecimal();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a {@link BigInteger} if it contains a single element. * convenience method to get this array as a {@link BigInteger} if it contains a single element.
* *
* @return get this element as a {@link BigInteger} if it is single element array. * @return get this element as a {@link BigInteger} if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}. * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
* @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}. * @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
* @since 1.2 * @since 1.2
*/ */
@Override @Override
public BigInteger getAsBigInteger() { public BigInteger getAsBigInteger() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsBigInteger(); return elements.get(0).getAsBigInteger();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a float if it contains a single element. * convenience method to get this array as a float if it contains a single element.
* *
* @return get this element as a float if it is single element array. * @return get this element as a float if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid float. * is not a valid float.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public float getAsFloat() { public float getAsFloat() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsFloat(); return elements.get(0).getAsFloat();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a long if it contains a single element. * convenience method to get this array as a long if it contains a single element.
* *
* @return get this element as a long if it is single element array. * @return get this element as a long if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid long. * is not a valid long.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public long getAsLong() { public long getAsLong() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsLong(); return elements.get(0).getAsLong();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as an integer if it contains a single element. * convenience method to get this array as an integer if it contains a single element.
* *
* @return get this element as an integer if it is single element array. * @return get this element as an integer if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid integer. * is not a valid integer.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public int getAsInt() { public int getAsInt() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsInt(); return elements.get(0).getAsInt();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
@Override @Override
public byte getAsByte() { public byte getAsByte() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsByte(); return elements.get(0).getAsByte();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
@Override @Override
public char getAsCharacter() { public char getAsCharacter() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsCharacter(); return elements.get(0).getAsCharacter();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a primitive short if it contains a single element. * convenience method to get this array as a primitive short if it contains a single element.
* *
* @return get this element as a primitive short if it is single element array. * @return get this element as a primitive short if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid short. * is not a valid short.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public short getAsShort() { public short getAsShort() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsShort(); return elements.get(0).getAsShort();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
/** /**
* convenience method to get this array as a boolean if it contains a single element. * convenience method to get this array as a boolean if it contains a single element.
* *
* @return get this element as a boolean if it is single element array. * @return get this element as a boolean if it is single element array.
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
* is not a valid boolean. * is not a valid boolean.
* @throws IllegalStateException if the array has more than one element. * @throws IllegalStateException if the array has more than one element.
*/ */
@Override @Override
public boolean getAsBoolean() { public boolean getAsBoolean() {
if (elements.size() == 1) { if (elements.size() == 1) {
return elements.get(0).getAsBoolean(); return elements.get(0).getAsBoolean();
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements)); return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements));
} }
@Override @Override
public int hashCode() { public int hashCode() {
return elements.hashCode(); return elements.hashCode();
} }
} }
@@ -1,44 +1,44 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* Context for deserialization that is passed to a custom deserializer during invocation of its * Context for deserialization that is passed to a custom deserializer during invocation of its
* {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)}
* method. * method.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public interface JsonDeserializationContext { public interface JsonDeserializationContext {
/** /**
* Invokes default deserialization on the specified object. It should never be invoked on * Invokes default deserialization on the specified object. It should never be invoked on
* the element received as a parameter of the * the element received as a parameter of the
* {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} method. Doing * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} method. Doing
* so will result in an infinite loop since Gson will in-turn call the custom deserializer again. * so will result in an infinite loop since Gson will in-turn call the custom deserializer again.
* *
* @param json the parse tree. * @param json the parse tree.
* @param typeOfT type of the expected return value. * @param typeOfT type of the expected return value.
* @param <T> The type of the deserialized object. * @param <T> The type of the deserialized object.
* @return An object of type typeOfT. * @return An object of type typeOfT.
* @throws JsonParseException if the parse tree does not contain expected data. * @throws JsonParseException if the parse tree does not contain expected data.
*/ */
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException; public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;
} }
+91 -91
View File
@@ -1,91 +1,91 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* <p>Interface representing a custom deserializer for Json. You should write a custom * <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 * deserializer, if you are not happy with the default deserialization done by Gson. You will
* also need to register this deserializer through * also need to register this deserializer through
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}.</p> * {@link GsonBuilder#registerTypeAdapter(Type, Object)}.</p>
* *
* <p>Let us look at example where defining a deserializer will be useful. The {@code Id} class * <p>Let us look at example where defining a deserializer will be useful. The {@code Id} class
* defined below has two fields: {@code clazz} and {@code value}.</p> * defined below has two fields: {@code clazz} and {@code value}.</p>
* *
* <pre> * <pre>
* public class Id&lt;T&gt; { * public class Id&lt;T&gt; {
* private final Class&lt;T&gt; clazz; * private final Class&lt;T&gt; clazz;
* private final long value; * private final long value;
* public Id(Class&lt;T&gt; clazz, long value) { * public Id(Class&lt;T&gt; clazz, long value) {
* this.clazz = clazz; * this.clazz = clazz;
* this.value = value; * this.value = value;
* } * }
* public long getValue() { * public long getValue() {
* return value; * return value;
* } * }
* } * }
* </pre> * </pre>
* *
* <p>The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the * <p>The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the
* Json string to be <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you already know * Json string to be <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you already know
* the type of the field that the {@code Id} will be deserialized into, and hence just want to * the type of the field that the {@code Id} will be deserialized into, and hence just want to
* deserialize it from a Json string {@code 20}. You can achieve that by writing a custom * deserialize it from a Json string {@code 20}. You can achieve that by writing a custom
* deserializer:</p> * deserializer:</p>
* *
* <pre> * <pre>
* class IdDeserializer implements JsonDeserializer&lt;Id&gt;() { * class IdDeserializer implements JsonDeserializer&lt;Id&gt;() {
* public Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) * public Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
* throws JsonParseException { * throws JsonParseException {
* return new Id((Class)typeOfT, id.getValue()); * return new Id((Class)typeOfT, id.getValue());
* } * }
* </pre> * </pre>
* *
* <p>You will also need to register {@code IdDeserializer} with Gson as follows:</p> * <p>You will also need to register {@code IdDeserializer} with Gson as follows:</p>
* *
* <pre> * <pre>
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdDeserializer()).create(); * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdDeserializer()).create();
* </pre> * </pre>
* *
* <p>New applications should prefer {@link TypeAdapter}, whose streaming API * <p>New applications should prefer {@link TypeAdapter}, whose streaming API
* is more efficient than this interface's tree API. * is more efficient than this interface's tree API.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* *
* @param <T> type for which the deserializer is being registered. It is possible that a * @param <T> type for which the deserializer is being registered. It is possible that a
* deserializer may be asked to deserialize a specific generic type of the T. * deserializer may be asked to deserialize a specific generic type of the T.
*/ */
public interface JsonDeserializer<T> { public interface JsonDeserializer<T> {
/** /**
* Gson invokes this call-back method during deserialization when it encounters a field of the * Gson invokes this call-back method during deserialization when it encounters a field of the
* specified type. * specified type.
* <p>In the implementation of this call-back method, you should consider invoking * <p>In the implementation of this call-back method, you should consider invoking
* {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects * {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects
* for any non-trivial field of the returned object. However, you should never invoke it on the * for any non-trivial field of the returned object. However, you should never invoke it on the
* the same type passing {@code json} since that will cause an infinite loop (Gson will call your * the same type passing {@code json} since that will cause an infinite loop (Gson will call your
* call-back method again). * call-back method again).
* *
* @param json The Json data being deserialized * @param json The Json data being deserialized
* @param typeOfT The type of the Object to deserialize to * @param typeOfT The type of the Object to deserialize to
* @return a deserialized object of the specified type typeOfT which is a subclass of {@code T} * @return a deserialized object of the specified type typeOfT which is a subclass of {@code T}
* @throws JsonParseException if json is not in the expected format of {@code typeofT} * @throws JsonParseException if json is not in the expected format of {@code typeofT}
*/ */
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException; throws JsonParseException;
} }
+324 -324
View File
@@ -1,324 +1,324 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.internal.Streams; import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
/** /**
* A class representing an element of Json. It could either be a {@link JsonObject}, a * A class representing an element of Json. It could either be a {@link JsonObject}, a
* {@link JsonArray}, a {@link JsonPrimitive} or a {@link JsonNull}. * {@link JsonArray}, a {@link JsonPrimitive} or a {@link JsonNull}.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public abstract class JsonElement { public abstract class JsonElement {
/** /**
* provides check for verifying if this element is an array or not. * provides check for verifying if this element is an array or not.
* *
* @return true if this element is of type {@link JsonArray}, false otherwise. * @return true if this element is of type {@link JsonArray}, false otherwise.
*/ */
public boolean isJsonArray() { public boolean isJsonArray() {
return this instanceof JsonArray; return this instanceof JsonArray;
} }
/** /**
* provides check for verifying if this element is a Json object or not. * provides check for verifying if this element is a Json object or not.
* *
* @return true if this element is of type {@link JsonObject}, false otherwise. * @return true if this element is of type {@link JsonObject}, false otherwise.
*/ */
public boolean isJsonObject() { public boolean isJsonObject() {
return this instanceof JsonObject; return this instanceof JsonObject;
} }
/** /**
* provides check for verifying if this element is a primitive or not. * provides check for verifying if this element is a primitive or not.
* *
* @return true if this element is of type {@link JsonPrimitive}, false otherwise. * @return true if this element is of type {@link JsonPrimitive}, false otherwise.
*/ */
public boolean isJsonPrimitive() { public boolean isJsonPrimitive() {
return this instanceof JsonPrimitive; return this instanceof JsonPrimitive;
} }
/** /**
* provides check for verifying if this element represents a null value or not. * provides check for verifying if this element represents a null value or not.
* *
* @return true if this element is of type {@link JsonNull}, false otherwise. * @return true if this element is of type {@link JsonNull}, false otherwise.
* @since 1.2 * @since 1.2
*/ */
public boolean isJsonNull() { public boolean isJsonNull() {
return this instanceof JsonNull; return this instanceof JsonNull;
} }
/** /**
* convenience method to get this element as a {@link JsonObject}. If the element is of some * convenience method to get this element as a {@link JsonObject}. If the element is of some
* other type, a {@link ClassCastException} will result. Hence it is best to use this method * other type, a {@link ClassCastException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #isJsonObject()} * after ensuring that this element is of the desired type by calling {@link #isJsonObject()}
* first. * first.
* *
* @return get this element as a {@link JsonObject}. * @return get this element as a {@link JsonObject}.
* @throws IllegalStateException if the element is of another type. * @throws IllegalStateException if the element is of another type.
*/ */
public JsonObject getAsJsonObject() { public JsonObject getAsJsonObject() {
if (isJsonObject()) { if (isJsonObject()) {
return (JsonObject) this; return (JsonObject) this;
} }
throw new IllegalStateException("Not a JSON Object: " + this); throw new IllegalStateException("Not a JSON Object: " + this);
} }
/** /**
* convenience method to get this element as a {@link JsonArray}. If the element is of some * convenience method to get this element as a {@link JsonArray}. If the element is of some
* other type, a {@link ClassCastException} will result. Hence it is best to use this method * other type, a {@link ClassCastException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #isJsonArray()} * after ensuring that this element is of the desired type by calling {@link #isJsonArray()}
* first. * first.
* *
* @return get this element as a {@link JsonArray}. * @return get this element as a {@link JsonArray}.
* @throws IllegalStateException if the element is of another type. * @throws IllegalStateException if the element is of another type.
*/ */
public JsonArray getAsJsonArray() { public JsonArray getAsJsonArray() {
if (isJsonArray()) { if (isJsonArray()) {
return (JsonArray) this; return (JsonArray) this;
} }
throw new IllegalStateException("This is not a JSON Array."); throw new IllegalStateException("This is not a JSON Array.");
} }
/** /**
* convenience method to get this element as a {@link JsonPrimitive}. If the element is of some * convenience method to get this element as a {@link JsonPrimitive}. If the element is of some
* other type, a {@link ClassCastException} will result. Hence it is best to use this method * other type, a {@link ClassCastException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #isJsonPrimitive()} * after ensuring that this element is of the desired type by calling {@link #isJsonPrimitive()}
* first. * first.
* *
* @return get this element as a {@link JsonPrimitive}. * @return get this element as a {@link JsonPrimitive}.
* @throws IllegalStateException if the element is of another type. * @throws IllegalStateException if the element is of another type.
*/ */
public JsonPrimitive getAsJsonPrimitive() { public JsonPrimitive getAsJsonPrimitive() {
if (isJsonPrimitive()) { if (isJsonPrimitive()) {
return (JsonPrimitive) this; return (JsonPrimitive) this;
} }
throw new IllegalStateException("This is not a JSON Primitive."); throw new IllegalStateException("This is not a JSON Primitive.");
} }
/** /**
* convenience method to get this element as a {@link JsonNull}. If the element is of some * convenience method to get this element as a {@link JsonNull}. If the element is of some
* other type, a {@link ClassCastException} will result. Hence it is best to use this method * other type, a {@link ClassCastException} will result. Hence it is best to use this method
* after ensuring that this element is of the desired type by calling {@link #isJsonNull()} * after ensuring that this element is of the desired type by calling {@link #isJsonNull()}
* first. * first.
* *
* @return get this element as a {@link JsonNull}. * @return get this element as a {@link JsonNull}.
* @throws IllegalStateException if the element is of another type. * @throws IllegalStateException if the element is of another type.
* @since 1.2 * @since 1.2
*/ */
public JsonNull getAsJsonNull() { public JsonNull getAsJsonNull() {
if (isJsonNull()) { if (isJsonNull()) {
return (JsonNull) this; return (JsonNull) this;
} }
throw new IllegalStateException("This is not a JSON Null."); throw new IllegalStateException("This is not a JSON Null.");
} }
/** /**
* convenience method to get this element as a boolean value. * convenience method to get this element as a boolean value.
* *
* @return get this element as a primitive boolean value. * @return get this element as a primitive boolean value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* boolean value. * boolean value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public boolean getAsBoolean() { public boolean getAsBoolean() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a {@link Boolean} value. * convenience method to get this element as a {@link Boolean} value.
* *
* @return get this element as a {@link Boolean} value. * @return get this element as a {@link Boolean} value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* boolean value. * boolean value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
Boolean getAsBooleanWrapper() { Boolean getAsBooleanWrapper() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a {@link Number}. * convenience method to get this element as a {@link Number}.
* *
* @return get this element as a {@link Number}. * @return get this element as a {@link Number}.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* number. * number.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public Number getAsNumber() { public Number getAsNumber() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a string value. * convenience method to get this element as a string value.
* *
* @return get this element as a string value. * @return get this element as a string value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* string value. * string value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public String getAsString() { public String getAsString() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a primitive double value. * convenience method to get this element as a primitive double value.
* *
* @return get this element as a primitive double value. * @return get this element as a primitive double value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* double value. * double value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public double getAsDouble() { public double getAsDouble() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a primitive float value. * convenience method to get this element as a primitive float value.
* *
* @return get this element as a primitive float value. * @return get this element as a primitive float value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* float value. * float value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public float getAsFloat() { public float getAsFloat() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a primitive long value. * convenience method to get this element as a primitive long value.
* *
* @return get this element as a primitive long value. * @return get this element as a primitive long value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* long value. * long value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public long getAsLong() { public long getAsLong() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a primitive integer value. * convenience method to get this element as a primitive integer value.
* *
* @return get this element as a primitive integer value. * @return get this element as a primitive integer value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* integer value. * integer value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public int getAsInt() { public int getAsInt() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a primitive byte value. * convenience method to get this element as a primitive byte value.
* *
* @return get this element as a primitive byte value. * @return get this element as a primitive byte value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* byte value. * byte value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
* @since 1.3 * @since 1.3
*/ */
public byte getAsByte() { public byte getAsByte() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a primitive character value. * convenience method to get this element as a primitive character value.
* *
* @return get this element as a primitive char value. * @return get this element as a primitive char value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* char value. * char value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
* @since 1.3 * @since 1.3
*/ */
public char getAsCharacter() { public char getAsCharacter() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a {@link BigDecimal}. * convenience method to get this element as a {@link BigDecimal}.
* *
* @return get this element as a {@link BigDecimal}. * @return get this element as a {@link BigDecimal}.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive}. * @throws ClassCastException if the element is of not a {@link JsonPrimitive}.
* * @throws NumberFormatException if the element is not a valid {@link BigDecimal}. * * @throws NumberFormatException if the element is not a valid {@link BigDecimal}.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
* @since 1.2 * @since 1.2
*/ */
public BigDecimal getAsBigDecimal() { public BigDecimal getAsBigDecimal() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a {@link BigInteger}. * convenience method to get this element as a {@link BigInteger}.
* *
* @return get this element as a {@link BigInteger}. * @return get this element as a {@link BigInteger}.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive}. * @throws ClassCastException if the element is of not a {@link JsonPrimitive}.
* @throws NumberFormatException if the element is not a valid {@link BigInteger}. * @throws NumberFormatException if the element is not a valid {@link BigInteger}.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
* @since 1.2 * @since 1.2
*/ */
public BigInteger getAsBigInteger() { public BigInteger getAsBigInteger() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* convenience method to get this element as a primitive short value. * convenience method to get this element as a primitive short value.
* *
* @return get this element as a primitive short value. * @return get this element as a primitive short value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* short value. * short value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element. * more than a single element.
*/ */
public short getAsShort() { public short getAsShort() {
throw new UnsupportedOperationException(getClass().getSimpleName()); throw new UnsupportedOperationException(getClass().getSimpleName());
} }
/** /**
* Returns a String representation of this element. * Returns a String representation of this element.
*/ */
@Override @Override
public String toString() { public String toString() {
try { try {
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter); JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.setLenient(true); jsonWriter.setLenient(true);
Streams.write(this, jsonWriter); Streams.write(this, jsonWriter);
return stringWriter.toString(); return stringWriter.toString();
} catch (IOException e) { } catch (IOException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
} }
+45 -45
View File
@@ -1,45 +1,45 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
/** /**
* This exception is raised when Gson was unable to read an input stream * This exception is raised when Gson was unable to read an input stream
* or write to one. * or write to one.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class JsonIOException extends JsonParseException { public final class JsonIOException extends JsonParseException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public JsonIOException(String msg) { public JsonIOException(String msg) {
super(msg); super(msg);
} }
public JsonIOException(String msg, Throwable cause) { public JsonIOException(String msg, Throwable cause) {
super(msg, cause); super(msg, cause);
} }
/** /**
* Creates exception with the specified cause. Consider using * Creates exception with the specified cause. Consider using
* {@link #JsonIOException(String, Throwable)} instead if you can describe what happened. * {@link #JsonIOException(String, Throwable)} instead if you can describe what happened.
* *
* @param cause root exception that caused this exception to be thrown. * @param cause root exception that caused this exception to be thrown.
*/ */
public JsonIOException(Throwable cause) { public JsonIOException(Throwable cause) {
super(cause); super(cause);
} }
} }
+199 -199
View File
@@ -1,199 +1,199 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.$Gson$Preconditions;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* A class representing an object type in Json. An object consists of name-value pairs where names * A class representing an object type in Json. An object consists of name-value pairs where names
* are strings, and values are any other type of {@link JsonElement}. This allows for a creating a * are strings, and values are any other type of {@link JsonElement}. This allows for a creating a
* tree of JsonElements. The member elements of this object are maintained in order they were added. * tree of JsonElements. The member elements of this object are maintained in order they were added.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class JsonObject extends JsonElement { public final class JsonObject extends JsonElement {
// We are using a linked hash map because it is important to preserve // We are using a linked hash map because it is important to preserve
// the order in which elements are inserted. This is needed to ensure // the order in which elements are inserted. This is needed to ensure
// that the fields of an object are inserted in the order they were // that the fields of an object are inserted in the order they were
// defined in the class. // defined in the class.
private final Map<String, JsonElement> members = new LinkedHashMap<String, JsonElement>(); private final Map<String, JsonElement> members = new LinkedHashMap<String, JsonElement>();
/** /**
* Creates an empty JsonObject. * Creates an empty JsonObject.
*/ */
public JsonObject() { public JsonObject() {
} }
/** /**
* Adds a member, which is a name-value pair, to self. The name must be a String, but the value * Adds a member, which is a name-value pair, to self. The name must be a String, but the value
* can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements * can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements
* rooted at this node. * rooted at this node.
* *
* @param property name of the member. * @param property name of the member.
* @param value the member object. * @param value the member object.
*/ */
public void add(String property, JsonElement value) { public void add(String property, JsonElement value) {
if (value == null) { if (value == null) {
value = JsonNull.INSTANCE; value = JsonNull.INSTANCE;
} }
members.put($Gson$Preconditions.checkNotNull(property), value); members.put($Gson$Preconditions.checkNotNull(property), value);
} }
/** /**
* Removes the {@code property} from this {@link JsonObject}. * Removes the {@code property} from this {@link JsonObject}.
* *
* @param property name of the member that should be removed. * @param property name of the member that should be removed.
* @return the {@link JsonElement} object that is being removed. * @return the {@link JsonElement} object that is being removed.
* @since 1.3 * @since 1.3
*/ */
public JsonElement remove(String property) { public JsonElement remove(String property) {
return members.remove(property); return members.remove(property);
} }
/** /**
* Convenience method to add a primitive member. The specified value is converted to a * Convenience method to add a primitive member. The specified value is converted to a
* JsonPrimitive of String. * JsonPrimitive of String.
* *
* @param property name of the member. * @param property name of the member.
* @param value the string value associated with the member. * @param value the string value associated with the member.
*/ */
public void addProperty(String property, String value) { public void addProperty(String property, String value) {
add(property, createJsonElement(value)); add(property, createJsonElement(value));
} }
/** /**
* Convenience method to add a primitive member. The specified value is converted to a * Convenience method to add a primitive member. The specified value is converted to a
* JsonPrimitive of Number. * JsonPrimitive of Number.
* *
* @param property name of the member. * @param property name of the member.
* @param value the number value associated with the member. * @param value the number value associated with the member.
*/ */
public void addProperty(String property, Number value) { public void addProperty(String property, Number value) {
add(property, createJsonElement(value)); add(property, createJsonElement(value));
} }
/** /**
* Convenience method to add a boolean member. The specified value is converted to a * Convenience method to add a boolean member. The specified value is converted to a
* JsonPrimitive of Boolean. * JsonPrimitive of Boolean.
* *
* @param property name of the member. * @param property name of the member.
* @param value the number value associated with the member. * @param value the number value associated with the member.
*/ */
public void addProperty(String property, Boolean value) { public void addProperty(String property, Boolean value) {
add(property, createJsonElement(value)); add(property, createJsonElement(value));
} }
/** /**
* Convenience method to add a char member. The specified value is converted to a * Convenience method to add a char member. The specified value is converted to a
* JsonPrimitive of Character. * JsonPrimitive of Character.
* *
* @param property name of the member. * @param property name of the member.
* @param value the number value associated with the member. * @param value the number value associated with the member.
*/ */
public void addProperty(String property, Character value) { public void addProperty(String property, Character value) {
add(property, createJsonElement(value)); add(property, createJsonElement(value));
} }
/** /**
* Creates the proper {@link JsonElement} object from the given {@code value} object. * Creates the proper {@link JsonElement} object from the given {@code value} object.
* *
* @param value the object to generate the {@link JsonElement} for * @param value the object to generate the {@link JsonElement} for
* @return a {@link JsonPrimitive} if the {@code value} is not null, otherwise a {@link JsonNull} * @return a {@link JsonPrimitive} if the {@code value} is not null, otherwise a {@link JsonNull}
*/ */
private JsonElement createJsonElement(Object value) { private JsonElement createJsonElement(Object value) {
return value == null ? JsonNull.INSTANCE : new JsonPrimitive(value); return value == null ? JsonNull.INSTANCE : new JsonPrimitive(value);
} }
/** /**
* Returns a set of members of this object. The set is ordered, and the order is in which the * Returns a set of members of this object. The set is ordered, and the order is in which the
* elements were added. * elements were added.
* *
* @return a set of members of this object. * @return a set of members of this object.
*/ */
public Set<Map.Entry<String, JsonElement>> entrySet() { public Set<Map.Entry<String, JsonElement>> entrySet() {
return members.entrySet(); return members.entrySet();
} }
/** /**
* Convenience method to check if a member with the specified name is present in this object. * Convenience method to check if a member with the specified name is present in this object.
* *
* @param memberName name of the member that is being checked for presence. * @param memberName name of the member that is being checked for presence.
* @return true if there is a member with the specified name, false otherwise. * @return true if there is a member with the specified name, false otherwise.
*/ */
public boolean has(String memberName) { public boolean has(String memberName) {
return members.containsKey(memberName); return members.containsKey(memberName);
} }
/** /**
* Returns the member with the specified name. * Returns the member with the specified name.
* *
* @param memberName name of the member that is being requested. * @param memberName name of the member that is being requested.
* @return the member matching the name. Null if no such member exists. * @return the member matching the name. Null if no such member exists.
*/ */
public JsonElement get(String memberName) { public JsonElement get(String memberName) {
if (members.containsKey(memberName)) { if (members.containsKey(memberName)) {
JsonElement member = members.get(memberName); JsonElement member = members.get(memberName);
return member == null ? JsonNull.INSTANCE : member; return member == null ? JsonNull.INSTANCE : member;
} }
return null; return null;
} }
/** /**
* Convenience method to get the specified member as a JsonPrimitive element. * Convenience method to get the specified member as a JsonPrimitive element.
* *
* @param memberName name of the member being requested. * @param memberName name of the member being requested.
* @return the JsonPrimitive corresponding to the specified member. * @return the JsonPrimitive corresponding to the specified member.
*/ */
public JsonPrimitive getAsJsonPrimitive(String memberName) { public JsonPrimitive getAsJsonPrimitive(String memberName) {
return (JsonPrimitive) members.get(memberName); return (JsonPrimitive) members.get(memberName);
} }
/** /**
* Convenience method to get the specified member as a JsonArray. * Convenience method to get the specified member as a JsonArray.
* *
* @param memberName name of the member being requested. * @param memberName name of the member being requested.
* @return the JsonArray corresponding to the specified member. * @return the JsonArray corresponding to the specified member.
*/ */
public JsonArray getAsJsonArray(String memberName) { public JsonArray getAsJsonArray(String memberName) {
return (JsonArray) members.get(memberName); return (JsonArray) members.get(memberName);
} }
/** /**
* Convenience method to get the specified member as a JsonObject. * Convenience method to get the specified member as a JsonObject.
* *
* @param memberName name of the member being requested. * @param memberName name of the member being requested.
* @return the JsonObject corresponding to the specified member. * @return the JsonObject corresponding to the specified member.
*/ */
public JsonObject getAsJsonObject(String memberName) { public JsonObject getAsJsonObject(String memberName) {
return (JsonObject) members.get(memberName); return (JsonObject) members.get(memberName);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return (o == this) || (o instanceof JsonObject return (o == this) || (o instanceof JsonObject
&& ((JsonObject) o).members.equals(members)); && ((JsonObject) o).members.equals(members));
} }
@Override @Override
public int hashCode() { public int hashCode() {
return members.hashCode(); return members.hashCode();
} }
} }
+64 -64
View File
@@ -1,64 +1,64 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
/** /**
* This exception is raised if there is a serious issue that occurs during parsing of a Json * 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 * string. One of the main usages for this class is for the Gson infrastructure. If the incoming
* Json is bad/malicious, an instance of this exception is raised. * Json is bad/malicious, an instance of this exception is raised.
* *
* <p>This exception is a {@link RuntimeException} because it is exposed to the client. Using a * <p>This exception is a {@link RuntimeException} because it is exposed to the client. Using a
* {@link RuntimeException} avoids bad coding practices on the client side where they catch the * {@link RuntimeException} avoids bad coding practices on the client side where they catch the
* exception and do nothing. It is often the case that you want to blow up if there is a parsing * exception and do nothing. It is often the case that you want to blow up if there is a parsing
* error (i.e. often clients do not know how to recover from a {@link JsonParseException}.</p> * error (i.e. often clients do not know how to recover from a {@link JsonParseException}.</p>
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public class JsonParseException extends RuntimeException { public class JsonParseException extends RuntimeException {
static final long serialVersionUID = -4086729973971783390L; static final long serialVersionUID = -4086729973971783390L;
/** /**
* Creates exception with the specified message. If you are wrapping another exception, consider * Creates exception with the specified message. If you are wrapping another exception, consider
* using {@link #JsonParseException(String, Throwable)} instead. * using {@link #JsonParseException(String, Throwable)} instead.
* *
* @param msg error message describing a possible cause of this exception. * @param msg error message describing a possible cause of this exception.
*/ */
public JsonParseException(String msg) { public JsonParseException(String msg) {
super(msg); super(msg);
} }
/** /**
* Creates exception with the specified message and cause. * Creates exception with the specified message and cause.
* *
* @param msg error message describing what happened. * @param msg error message describing what happened.
* @param cause root exception that caused this exception to be thrown. * @param cause root exception that caused this exception to be thrown.
*/ */
public JsonParseException(String msg, Throwable cause) { public JsonParseException(String msg, Throwable cause) {
super(msg, cause); super(msg, cause);
} }
/** /**
* Creates exception with the specified cause. Consider using * Creates exception with the specified cause. Consider using
* {@link #JsonParseException(String, Throwable)} instead if you can describe what happened. * {@link #JsonParseException(String, Throwable)} instead if you can describe what happened.
* *
* @param cause root exception that caused this exception to be thrown. * @param cause root exception that caused this exception to be thrown.
*/ */
public JsonParseException(Throwable cause) { public JsonParseException(Throwable cause) {
super(cause); super(cause);
} }
} }
+336 -336
View File
@@ -1,336 +1,336 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.$Gson$Preconditions;
import com.google.gson.internal.LazilyParsedNumber; import com.google.gson.internal.LazilyParsedNumber;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
/** /**
* A class representing a Json primitive value. A primitive value * A class representing a Json primitive value. A primitive value
* is either a String, a Java primitive, or a Java primitive * is either a String, a Java primitive, or a Java primitive
* wrapper type. * wrapper type.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class JsonPrimitive extends JsonElement { public final class JsonPrimitive extends JsonElement {
private static final Class<?>[] PRIMITIVE_TYPES = { int.class, long.class, short.class, private static final Class<?>[] PRIMITIVE_TYPES = { int.class, long.class, short.class,
float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class, float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class,
Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class }; Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };
private Object value; private Object value;
/** /**
* Create a primitive containing a boolean value. * Create a primitive containing a boolean value.
* *
* @param bool the value to create the primitive with. * @param bool the value to create the primitive with.
*/ */
public JsonPrimitive(Boolean bool) { public JsonPrimitive(Boolean bool) {
setValue(bool); setValue(bool);
} }
/** /**
* Create a primitive containing a {@link Number}. * Create a primitive containing a {@link Number}.
* *
* @param number the value to create the primitive with. * @param number the value to create the primitive with.
*/ */
public JsonPrimitive(Number number) { public JsonPrimitive(Number number) {
setValue(number); setValue(number);
} }
/** /**
* Create a primitive containing a String value. * Create a primitive containing a String value.
* *
* @param string the value to create the primitive with. * @param string the value to create the primitive with.
*/ */
public JsonPrimitive(String string) { public JsonPrimitive(String string) {
setValue(string); setValue(string);
} }
/** /**
* Create a primitive containing a character. The character is turned into a one character String * Create a primitive containing a character. The character is turned into a one character String
* since Json only supports String. * since Json only supports String.
* *
* @param c the value to create the primitive with. * @param c the value to create the primitive with.
*/ */
public JsonPrimitive(Character c) { public JsonPrimitive(Character c) {
setValue(c); setValue(c);
} }
/** /**
* Create a primitive using the specified Object. It must be an instance of {@link Number}, a * Create a primitive using the specified Object. It must be an instance of {@link Number}, a
* Java primitive type, or a String. * Java primitive type, or a String.
* *
* @param primitive the value to create the primitive with. * @param primitive the value to create the primitive with.
*/ */
JsonPrimitive(Object primitive) { JsonPrimitive(Object primitive) {
setValue(primitive); setValue(primitive);
} }
void setValue(Object primitive) { void setValue(Object primitive) {
if (primitive instanceof Character) { if (primitive instanceof Character) {
// convert characters to strings since in JSON, characters are represented as a single // convert characters to strings since in JSON, characters are represented as a single
// character string // character string
char c = ((Character) primitive).charValue(); char c = ((Character) primitive).charValue();
this.value = String.valueOf(c); this.value = String.valueOf(c);
} else { } else {
$Gson$Preconditions.checkArgument(primitive instanceof Number $Gson$Preconditions.checkArgument(primitive instanceof Number
|| isPrimitiveOrString(primitive)); || isPrimitiveOrString(primitive));
this.value = primitive; this.value = primitive;
} }
} }
/** /**
* Check whether this primitive contains a boolean value. * Check whether this primitive contains a boolean value.
* *
* @return true if this primitive contains a boolean value, false otherwise. * @return true if this primitive contains a boolean value, false otherwise.
*/ */
public boolean isBoolean() { public boolean isBoolean() {
return value instanceof Boolean; return value instanceof Boolean;
} }
/** /**
* convenience method to get this element as a {@link Boolean}. * convenience method to get this element as a {@link Boolean}.
* *
* @return get this element as a {@link Boolean}. * @return get this element as a {@link Boolean}.
*/ */
@Override @Override
Boolean getAsBooleanWrapper() { Boolean getAsBooleanWrapper() {
return (Boolean) value; return (Boolean) value;
} }
/** /**
* convenience method to get this element as a boolean value. * convenience method to get this element as a boolean value.
* *
* @return get this element as a primitive boolean value. * @return get this element as a primitive boolean value.
*/ */
@Override @Override
public boolean getAsBoolean() { public boolean getAsBoolean() {
if (isBoolean()) { if (isBoolean()) {
return getAsBooleanWrapper().booleanValue(); return getAsBooleanWrapper().booleanValue();
} else { } else {
// Check to see if the value as a String is "true" in any case. // Check to see if the value as a String is "true" in any case.
return Boolean.parseBoolean(getAsString()); return Boolean.parseBoolean(getAsString());
} }
} }
/** /**
* Check whether this primitive contains a Number. * Check whether this primitive contains a Number.
* *
* @return true if this primitive contains a Number, false otherwise. * @return true if this primitive contains a Number, false otherwise.
*/ */
public boolean isNumber() { public boolean isNumber() {
return value instanceof Number; return value instanceof Number;
} }
/** /**
* convenience method to get this element as a Number. * convenience method to get this element as a Number.
* *
* @return get this element as a Number. * @return get this element as a Number.
* @throws NumberFormatException if the value contained is not a valid Number. * @throws NumberFormatException if the value contained is not a valid Number.
*/ */
@Override @Override
public Number getAsNumber() { public Number getAsNumber() {
return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value; return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value;
} }
/** /**
* Check whether this primitive contains a String value. * Check whether this primitive contains a String value.
* *
* @return true if this primitive contains a String value, false otherwise. * @return true if this primitive contains a String value, false otherwise.
*/ */
public boolean isString() { public boolean isString() {
return value instanceof String; return value instanceof String;
} }
/** /**
* convenience method to get this element as a String. * convenience method to get this element as a String.
* *
* @return get this element as a String. * @return get this element as a String.
*/ */
@Override @Override
public String getAsString() { public String getAsString() {
if (isNumber()) { if (isNumber()) {
return getAsNumber().toString(); return getAsNumber().toString();
} else if (isBoolean()) { } else if (isBoolean()) {
return getAsBooleanWrapper().toString(); return getAsBooleanWrapper().toString();
} else { } else {
return (String) value; return (String) value;
} }
} }
/** /**
* convenience method to get this element as a primitive double. * convenience method to get this element as a primitive double.
* *
* @return get this element as a primitive double. * @return get this element as a primitive double.
* @throws NumberFormatException if the value contained is not a valid double. * @throws NumberFormatException if the value contained is not a valid double.
*/ */
@Override @Override
public double getAsDouble() { public double getAsDouble() {
return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString()); return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString());
} }
/** /**
* convenience method to get this element as a {@link BigDecimal}. * convenience method to get this element as a {@link BigDecimal}.
* *
* @return get this element as a {@link BigDecimal}. * @return get this element as a {@link BigDecimal}.
* @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}. * @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}.
*/ */
@Override @Override
public BigDecimal getAsBigDecimal() { public BigDecimal getAsBigDecimal() {
return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString()); return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());
} }
/** /**
* convenience method to get this element as a {@link BigInteger}. * convenience method to get this element as a {@link BigInteger}.
* *
* @return get this element as a {@link BigInteger}. * @return get this element as a {@link BigInteger}.
* @throws NumberFormatException if the value contained is not a valid {@link BigInteger}. * @throws NumberFormatException if the value contained is not a valid {@link BigInteger}.
*/ */
@Override @Override
public BigInteger getAsBigInteger() { public BigInteger getAsBigInteger() {
return value instanceof BigInteger ? return value instanceof BigInteger ?
(BigInteger) value : new BigInteger(value.toString()); (BigInteger) value : new BigInteger(value.toString());
} }
/** /**
* convenience method to get this element as a float. * convenience method to get this element as a float.
* *
* @return get this element as a float. * @return get this element as a float.
* @throws NumberFormatException if the value contained is not a valid float. * @throws NumberFormatException if the value contained is not a valid float.
*/ */
@Override @Override
public float getAsFloat() { public float getAsFloat() {
return isNumber() ? getAsNumber().floatValue() : Float.parseFloat(getAsString()); return isNumber() ? getAsNumber().floatValue() : Float.parseFloat(getAsString());
} }
/** /**
* convenience method to get this element as a primitive long. * convenience method to get this element as a primitive long.
* *
* @return get this element as a primitive long. * @return get this element as a primitive long.
* @throws NumberFormatException if the value contained is not a valid long. * @throws NumberFormatException if the value contained is not a valid long.
*/ */
@Override @Override
public long getAsLong() { public long getAsLong() {
return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString()); return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString());
} }
/** /**
* convenience method to get this element as a primitive short. * convenience method to get this element as a primitive short.
* *
* @return get this element as a primitive short. * @return get this element as a primitive short.
* @throws NumberFormatException if the value contained is not a valid short value. * @throws NumberFormatException if the value contained is not a valid short value.
*/ */
@Override @Override
public short getAsShort() { public short getAsShort() {
return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString()); return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString());
} }
/** /**
* convenience method to get this element as a primitive integer. * convenience method to get this element as a primitive integer.
* *
* @return get this element as a primitive integer. * @return get this element as a primitive integer.
* @throws NumberFormatException if the value contained is not a valid integer. * @throws NumberFormatException if the value contained is not a valid integer.
*/ */
@Override @Override
public int getAsInt() { public int getAsInt() {
return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString()); return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString());
} }
@Override @Override
public byte getAsByte() { public byte getAsByte() {
return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString()); return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString());
} }
@Override @Override
public char getAsCharacter() { public char getAsCharacter() {
return getAsString().charAt(0); return getAsString().charAt(0);
} }
private static boolean isPrimitiveOrString(Object target) { private static boolean isPrimitiveOrString(Object target) {
if (target instanceof String) { if (target instanceof String) {
return true; return true;
} }
Class<?> classOfPrimitive = target.getClass(); Class<?> classOfPrimitive = target.getClass();
for (Class<?> standardPrimitive : PRIMITIVE_TYPES) { for (Class<?> standardPrimitive : PRIMITIVE_TYPES) {
if (standardPrimitive.isAssignableFrom(classOfPrimitive)) { if (standardPrimitive.isAssignableFrom(classOfPrimitive)) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public int hashCode() { public int hashCode() {
if (value == null) { if (value == null) {
return 31; return 31;
} }
// Using recommended hashing algorithm from Effective Java for longs and doubles // Using recommended hashing algorithm from Effective Java for longs and doubles
if (isIntegral(this)) { if (isIntegral(this)) {
long value = getAsNumber().longValue(); long value = getAsNumber().longValue();
return (int) (value ^ (value >>> 32)); return (int) (value ^ (value >>> 32));
} }
if (value instanceof Number) { if (value instanceof Number) {
long value = Double.doubleToLongBits(getAsNumber().doubleValue()); long value = Double.doubleToLongBits(getAsNumber().doubleValue());
return (int) (value ^ (value >>> 32)); return (int) (value ^ (value >>> 32));
} }
return value.hashCode(); return value.hashCode();
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj == null || getClass() != obj.getClass()) { if (obj == null || getClass() != obj.getClass()) {
return false; return false;
} }
JsonPrimitive other = (JsonPrimitive)obj; JsonPrimitive other = (JsonPrimitive)obj;
if (value == null) { if (value == null) {
return other.value == null; return other.value == null;
} }
if (isIntegral(this) && isIntegral(other)) { if (isIntegral(this) && isIntegral(other)) {
return getAsNumber().longValue() == other.getAsNumber().longValue(); return getAsNumber().longValue() == other.getAsNumber().longValue();
} }
if (value instanceof Number && other.value instanceof Number) { if (value instanceof Number && other.value instanceof Number) {
double a = getAsNumber().doubleValue(); double a = getAsNumber().doubleValue();
// Java standard types other than double return true for two NaN. So, need // Java standard types other than double return true for two NaN. So, need
// special handling for double. // special handling for double.
double b = other.getAsNumber().doubleValue(); double b = other.getAsNumber().doubleValue();
return a == b || (Double.isNaN(a) && Double.isNaN(b)); return a == b || (Double.isNaN(a) && Double.isNaN(b));
} }
return value.equals(other.value); return value.equals(other.value);
} }
/** /**
* Returns true if the specified number is an integral type * Returns true if the specified number is an integral type
* (Long, Integer, Short, Byte, BigInteger) * (Long, Integer, Short, Byte, BigInteger)
*/ */
private static boolean isIntegral(JsonPrimitive primitive) { private static boolean isIntegral(JsonPrimitive primitive) {
if (primitive.value instanceof Number) { if (primitive.value instanceof Number) {
Number number = (Number) primitive.value; Number number = (Number) primitive.value;
return number instanceof BigInteger || number instanceof Long || number instanceof Integer return number instanceof BigInteger || number instanceof Long || number instanceof Integer
|| number instanceof Short || number instanceof Byte; || number instanceof Short || number instanceof Byte;
} }
return false; return false;
} }
} }
@@ -1,49 +1,49 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* Context for serialization that is passed to a custom serializer during invocation of its * Context for serialization that is passed to a custom serializer during invocation of its
* {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method. * {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public interface JsonSerializationContext { public interface JsonSerializationContext {
/** /**
* Invokes default serialization on the specified object. * Invokes default serialization on the specified object.
* *
* @param src the object that needs to be serialized. * @param src the object that needs to be serialized.
* @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}. * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
*/ */
public JsonElement serialize(Object src); public JsonElement serialize(Object src);
/** /**
* Invokes default serialization on the specified object passing the specific type information. * Invokes default serialization on the specified object passing the specific type information.
* It should never be invoked on the element received as a parameter of the * It should never be invoked on the element received as a parameter of the
* {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method. Doing * {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method. Doing
* so will result in an infinite loop since Gson will in-turn call the custom serializer again. * so will result in an infinite loop since Gson will in-turn call the custom serializer again.
* *
* @param src the object that needs to be serialized. * @param src the object that needs to be serialized.
* @param typeOfSrc the actual genericized type of src object. * @param typeOfSrc the actual genericized type of src object.
* @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}. * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
*/ */
public JsonElement serialize(Object src, Type typeOfSrc); public JsonElement serialize(Object src, Type typeOfSrc);
} }
+89 -89
View File
@@ -1,89 +1,89 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* Interface representing a custom serializer for Json. You should write a custom serializer, if * 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 * you are not happy with the default serialization done by Gson. You will also need to register
* this serializer through {@link com.google.gson.GsonBuilder#registerTypeAdapter(Type, Object)}. * this serializer through {@link com.google.gson.GsonBuilder#registerTypeAdapter(Type, Object)}.
* *
* <p>Let us look at example where defining a serializer will be useful. The {@code Id} class * <p>Let us look at example where defining a serializer will be useful. The {@code Id} class
* defined below has two fields: {@code clazz} and {@code value}.</p> * defined below has two fields: {@code clazz} and {@code value}.</p>
* *
* <p><pre> * <p><pre>
* public class Id&lt;T&gt; { * public class Id&lt;T&gt; {
* private final Class&lt;T&gt; clazz; * private final Class&lt;T&gt; clazz;
* private final long value; * private final long value;
* *
* public Id(Class&lt;T&gt; clazz, long value) { * public Id(Class&lt;T&gt; clazz, long value) {
* this.clazz = clazz; * this.clazz = clazz;
* this.value = value; * this.value = value;
* } * }
* *
* public long getValue() { * public long getValue() {
* return value; * return value;
* } * }
* } * }
* </pre></p> * </pre></p>
* *
* <p>The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be * <p>The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be
* <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you just want the output to be * <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you just want the output to be
* the value instead, which is {@code 20} in this case. You can achieve that by writing a custom * the value instead, which is {@code 20} in this case. You can achieve that by writing a custom
* serializer:</p> * serializer:</p>
* *
* <p><pre> * <p><pre>
* class IdSerializer implements JsonSerializer&lt;Id&gt;() { * class IdSerializer implements JsonSerializer&lt;Id&gt;() {
* public JsonElement serialize(Id id, Type typeOfId, JsonSerializationContext context) { * public JsonElement serialize(Id id, Type typeOfId, JsonSerializationContext context) {
* return new JsonPrimitive(id.getValue()); * return new JsonPrimitive(id.getValue());
* } * }
* } * }
* </pre></p> * </pre></p>
* *
* <p>You will also need to register {@code IdSerializer} with Gson as follows:</p> * <p>You will also need to register {@code IdSerializer} with Gson as follows:</p>
* <pre> * <pre>
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).create(); * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).create();
* </pre> * </pre>
* *
* <p>New applications should prefer {@link TypeAdapter}, whose streaming API * <p>New applications should prefer {@link TypeAdapter}, whose streaming API
* is more efficient than this interface's tree API. * is more efficient than this interface's tree API.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* *
* @param <T> type for which the serializer is being registered. It is possible that a serializer * @param <T> type for which the serializer is being registered. It is possible that a serializer
* may be asked to serialize a specific generic type of the T. * may be asked to serialize a specific generic type of the T.
*/ */
public interface JsonSerializer<T> { public interface JsonSerializer<T> {
/** /**
* Gson invokes this call-back method during serialization when it encounters a field of the * Gson invokes this call-back method during serialization when it encounters a field of the
* specified type. * specified type.
* *
* <p>In the implementation of this call-back method, you should consider invoking * <p>In the implementation of this call-back method, you should consider invoking
* {@link JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any * {@link JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any
* non-trivial field of the {@code src} object. However, you should never invoke it on the * non-trivial field of the {@code src} object. However, you should never invoke it on the
* {@code src} object itself since that will cause an infinite loop (Gson will call your * {@code src} object itself since that will cause an infinite loop (Gson will call your
* call-back method again).</p> * call-back method again).</p>
* *
* @param src the object that needs to be converted to Json. * @param src the object that needs to be converted to Json.
* @param typeOfSrc the actual type (fully genericized version) of the source object. * @param typeOfSrc the actual type (fully genericized version) of the source object.
* @return a JsonElement corresponding to the specified object. * @return a JsonElement corresponding to the specified object.
*/ */
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context); public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);
} }
+122 -122
View File
@@ -1,122 +1,122 @@
/* /*
* Copyright (C) 2009 Google Inc. * Copyright (C) 2009 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import com.google.gson.internal.Streams; import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.MalformedJsonException; import com.google.gson.stream.MalformedJsonException;
/** /**
* A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader * A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
* asynchronously. * asynchronously.
* *
* <p>This class is conditionally thread-safe (see Item 70, Effective Java second edition). To * <p>This class is conditionally thread-safe (see Item 70, Effective Java second edition). To
* properly use this class across multiple threads, you will need to add some external * properly use this class across multiple threads, you will need to add some external
* synchronization. For example: * synchronization. For example:
* *
* <pre> * <pre>
* JsonStreamParser parser = new JsonStreamParser("['first'] {'second':10} 'third'"); * JsonStreamParser parser = new JsonStreamParser("['first'] {'second':10} 'third'");
* JsonElement element; * JsonElement element;
* synchronized (parser) { // synchronize on an object shared by threads * synchronized (parser) { // synchronize on an object shared by threads
* if (parser.hasNext()) { * if (parser.hasNext()) {
* element = parser.next(); * element = parser.next();
* } * }
* } * }
* </pre> * </pre>
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* @since 1.4 * @since 1.4
*/ */
public final class JsonStreamParser implements Iterator<JsonElement> { public final class JsonStreamParser implements Iterator<JsonElement> {
private final JsonReader parser; private final JsonReader parser;
private final Object lock; private final Object lock;
/** /**
* @param json The string containing JSON elements concatenated to each other. * @param json The string containing JSON elements concatenated to each other.
* @since 1.4 * @since 1.4
*/ */
public JsonStreamParser(String json) { public JsonStreamParser(String json) {
this(new StringReader(json)); this(new StringReader(json));
} }
/** /**
* @param reader The data stream containing JSON elements concatenated to each other. * @param reader The data stream containing JSON elements concatenated to each other.
* @since 1.4 * @since 1.4
*/ */
public JsonStreamParser(Reader reader) { public JsonStreamParser(Reader reader) {
parser = new JsonReader(reader); parser = new JsonReader(reader);
parser.setLenient(true); parser.setLenient(true);
lock = new Object(); lock = new Object();
} }
/** /**
* Returns the next available {@link JsonElement} on the reader. Null if none available. * Returns the next available {@link JsonElement} on the reader. Null if none available.
* *
* @return the next available {@link JsonElement} on the reader. Null if none available. * @return the next available {@link JsonElement} on the reader. Null if none available.
* @throws JsonParseException if the incoming stream is malformed JSON. * @throws JsonParseException if the incoming stream is malformed JSON.
* @since 1.4 * @since 1.4
*/ */
public JsonElement next() throws JsonParseException { public JsonElement next() throws JsonParseException {
if (!hasNext()) { if (!hasNext()) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
try { try {
return Streams.parse(parser); return Streams.parse(parser);
} catch (StackOverflowError e) { } catch (StackOverflowError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e); throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
throw new JsonParseException("Failed parsing JSON source to Json", e); throw new JsonParseException("Failed parsing JSON source to Json", e);
} catch (JsonParseException e) { } catch (JsonParseException e) {
throw e.getCause() instanceof EOFException ? new NoSuchElementException() : e; throw e.getCause() instanceof EOFException ? new NoSuchElementException() : e;
} }
} }
/** /**
* Returns true if a {@link JsonElement} is available on the input for consumption * Returns true if a {@link JsonElement} is available on the input for consumption
* @return true if a {@link JsonElement} is available on the input, false otherwise * @return true if a {@link JsonElement} is available on the input, false otherwise
* @since 1.4 * @since 1.4
*/ */
public boolean hasNext() { public boolean hasNext() {
synchronized (lock) { synchronized (lock) {
try { try {
return parser.peek() != JsonToken.END_DOCUMENT; return parser.peek() != JsonToken.END_DOCUMENT;
} catch (MalformedJsonException e) { } catch (MalformedJsonException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} catch (IOException e) { } catch (IOException e) {
throw new JsonIOException(e); throw new JsonIOException(e);
} }
} }
} }
/** /**
* This optional {@link Iterator} method is not relevant for stream parsing and hence is not * This optional {@link Iterator} method is not relevant for stream parsing and hence is not
* implemented. * implemented.
* @since 1.4 * @since 1.4
*/ */
public void remove() { public void remove() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
+47 -47
View File
@@ -1,47 +1,47 @@
/* /*
* Copyright (C) 2010 Google Inc. * Copyright (C) 2010 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
/** /**
* This exception is raised when Gson attempts to read (or write) a malformed * This exception is raised when Gson attempts to read (or write) a malformed
* JSON element. * JSON element.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class JsonSyntaxException extends JsonParseException { public final class JsonSyntaxException extends JsonParseException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public JsonSyntaxException(String msg) { public JsonSyntaxException(String msg) {
super(msg); super(msg);
} }
public JsonSyntaxException(String msg, Throwable cause) { public JsonSyntaxException(String msg, Throwable cause) {
super(msg, cause); super(msg, cause);
} }
/** /**
* Creates exception with the specified cause. Consider using * Creates exception with the specified cause. Consider using
* {@link #JsonSyntaxException(String, Throwable)} instead if you can * {@link #JsonSyntaxException(String, Throwable)} instead if you can
* describe what actually happened. * describe what actually happened.
* *
* @param cause root exception that caused this exception to be thrown. * @param cause root exception that caused this exception to be thrown.
*/ */
public JsonSyntaxException(Throwable cause) { public JsonSyntaxException(Throwable cause) {
super(cause); super(cause);
} }
} }
@@ -1,58 +1,58 @@
/* /*
* Copyright (C) 2009 Google Inc. * Copyright (C) 2009 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
/** /**
* Defines the expected format for a {@code long} or {@code Long} type when its serialized. * Defines the expected format for a {@code long} or {@code Long} type when its serialized.
* *
* @since 1.3 * @since 1.3
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public enum LongSerializationPolicy { public enum LongSerializationPolicy {
/** /**
* This is the "default" serialization policy that will output a {@code long} object as a JSON * This is the "default" serialization policy that will output a {@code long} object as a JSON
* number. For example, assume an object has a long field named "f" then the serialized output * number. For example, assume an object has a long field named "f" then the serialized output
* would be: * would be:
* {@code {"f":123}}. * {@code {"f":123}}.
*/ */
DEFAULT() { DEFAULT() {
public JsonElement serialize(Long value) { public JsonElement serialize(Long value) {
return new JsonPrimitive(value); return new JsonPrimitive(value);
} }
}, },
/** /**
* Serializes a long value as a quoted string. For example, assume an object has a long field * 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: * named "f" then the serialized output would be:
* {@code {"f":"123"}}. * {@code {"f":"123"}}.
*/ */
STRING() { STRING() {
public JsonElement serialize(Long value) { public JsonElement serialize(Long value) {
return new JsonPrimitive(String.valueOf(value)); return new JsonPrimitive(String.valueOf(value));
} }
}; };
/** /**
* Serialize this {@code value} using this serialization policy. * Serialize this {@code value} using this serialization policy.
* *
* @param value the long value to be serialized into a {@link JsonElement} * @param value the long value to be serialized into a {@link JsonElement}
* @return the serialized version of {@code value} * @return the serialized version of {@code value}
*/ */
public abstract JsonElement serialize(Long value); public abstract JsonElement serialize(Long value);
} }
+141 -141
View File
@@ -1,141 +1,141 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.$Gson$Preconditions;
import com.google.gson.internal.GsonInternalAccess; import com.google.gson.internal.GsonInternalAccess;
import com.google.gson.internal.Streams; import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
/** /**
* Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the * 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 * tree adapter may be serialization-only or deserialization-only, this class
* has a facility to lookup a delegate type adapter on demand. * has a facility to lookup a delegate type adapter on demand.
*/ */
final class TreeTypeAdapter<T> extends TypeAdapter<T> { final class TreeTypeAdapter<T> extends TypeAdapter<T> {
private final JsonSerializer<T> serializer; private final JsonSerializer<T> serializer;
private final JsonDeserializer<T> deserializer; private final JsonDeserializer<T> deserializer;
private final Gson gson; private final Gson gson;
private final TypeToken<T> typeToken; private final TypeToken<T> typeToken;
private final TypeAdapterFactory skipPast; private final TypeAdapterFactory skipPast;
/** The delegate is lazily created because it may not be needed, and creating it may fail. */ /** The delegate is lazily created because it may not be needed, and creating it may fail. */
private TypeAdapter<T> delegate; private TypeAdapter<T> delegate;
private TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, private TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) { Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
this.serializer = serializer; this.serializer = serializer;
this.deserializer = deserializer; this.deserializer = deserializer;
this.gson = gson; this.gson = gson;
this.typeToken = typeToken; this.typeToken = typeToken;
this.skipPast = skipPast; this.skipPast = skipPast;
} }
@Override public T read(JsonReader in) throws IOException { @Override public T read(JsonReader in) throws IOException {
if (deserializer == null) { if (deserializer == null) {
return delegate().read(in); return delegate().read(in);
} }
JsonElement value = Streams.parse(in); JsonElement value = Streams.parse(in);
if (value.isJsonNull()) { if (value.isJsonNull()) {
return null; return null;
} }
return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext); return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext);
} }
@Override public void write(JsonWriter out, T value) throws IOException { @Override public void write(JsonWriter out, T value) throws IOException {
if (serializer == null) { if (serializer == null) {
delegate().write(out, value); delegate().write(out, value);
return; return;
} }
if (value == null) { if (value == null) {
out.nullValue(); out.nullValue();
return; return;
} }
JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext); JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext);
Streams.write(tree, out); Streams.write(tree, out);
} }
private TypeAdapter<T> delegate() { private TypeAdapter<T> delegate() {
TypeAdapter<T> d = delegate; TypeAdapter<T> d = delegate;
return d != null return d != null
? d ? d
: (delegate = GsonInternalAccess.INSTANCE.getNextAdapter(gson, skipPast, typeToken)); : (delegate = GsonInternalAccess.INSTANCE.getNextAdapter(gson, skipPast, typeToken));
} }
/** /**
* Returns a new factory that will match each type against {@code exactType}. * Returns a new factory that will match each type against {@code exactType}.
*/ */
public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) { public static TypeAdapterFactory newFactory(TypeToken<?> exactType, Object typeAdapter) {
return new SingleTypeFactory(typeAdapter, exactType, false, null); return new SingleTypeFactory(typeAdapter, exactType, false, null);
} }
/** /**
* Returns a new factory that will match each type and its raw type against * Returns a new factory that will match each type and its raw type against
* {@code exactType}. * {@code exactType}.
*/ */
public static TypeAdapterFactory newFactoryWithMatchRawType( public static TypeAdapterFactory newFactoryWithMatchRawType(
TypeToken<?> exactType, Object typeAdapter) { TypeToken<?> exactType, Object typeAdapter) {
// only bother matching raw types if exact type is a raw type // only bother matching raw types if exact type is a raw type
boolean matchRawType = exactType.getType() == exactType.getRawType(); boolean matchRawType = exactType.getType() == exactType.getRawType();
return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null); return new SingleTypeFactory(typeAdapter, exactType, matchRawType, null);
} }
/** /**
* Returns a new factory that will match each type's raw type for assignability * Returns a new factory that will match each type's raw type for assignability
* to {@code hierarchyType}. * to {@code hierarchyType}.
*/ */
public static TypeAdapterFactory newTypeHierarchyFactory( public static TypeAdapterFactory newTypeHierarchyFactory(
Class<?> hierarchyType, Object typeAdapter) { Class<?> hierarchyType, Object typeAdapter) {
return new SingleTypeFactory(typeAdapter, null, false, hierarchyType); return new SingleTypeFactory(typeAdapter, null, false, hierarchyType);
} }
private static class SingleTypeFactory implements TypeAdapterFactory { private static class SingleTypeFactory implements TypeAdapterFactory {
private final TypeToken<?> exactType; private final TypeToken<?> exactType;
private final boolean matchRawType; private final boolean matchRawType;
private final Class<?> hierarchyType; private final Class<?> hierarchyType;
private final JsonSerializer<?> serializer; private final JsonSerializer<?> serializer;
private final JsonDeserializer<?> deserializer; private final JsonDeserializer<?> deserializer;
private SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, private SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType,
Class<?> hierarchyType) { Class<?> hierarchyType) {
serializer = typeAdapter instanceof JsonSerializer serializer = typeAdapter instanceof JsonSerializer
? (JsonSerializer<?>) typeAdapter ? (JsonSerializer<?>) typeAdapter
: null; : null;
deserializer = typeAdapter instanceof JsonDeserializer deserializer = typeAdapter instanceof JsonDeserializer
? (JsonDeserializer<?>) typeAdapter ? (JsonDeserializer<?>) typeAdapter
: null; : null;
$Gson$Preconditions.checkArgument(serializer != null || deserializer != null); $Gson$Preconditions.checkArgument(serializer != null || deserializer != null);
this.exactType = exactType; this.exactType = exactType;
this.matchRawType = matchRawType; this.matchRawType = matchRawType;
this.hierarchyType = hierarchyType; this.hierarchyType = hierarchyType;
} }
@SuppressWarnings("unchecked") // guarded by typeToken.equals() call @SuppressWarnings("unchecked") // guarded by typeToken.equals() call
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
boolean matches = exactType != null boolean matches = exactType != null
? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType() ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType()
: hierarchyType.isAssignableFrom(type.getRawType()); : hierarchyType.isAssignableFrom(type.getRawType());
return matches return matches
? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer, ? new TreeTypeAdapter<T>((JsonSerializer<T>) serializer,
(JsonDeserializer<T>) deserializer, gson, type, this) (JsonDeserializer<T>) deserializer, gson, type, this)
: null; : null;
} }
} }
} }
+283 -283
View File
@@ -1,283 +1,283 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.internal.bind.JsonTreeWriter;
import com.google.gson.internal.bind.JsonTreeReader; import com.google.gson.internal.bind.JsonTreeReader;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
/** /**
* Converts Java objects to and from JSON. * Converts Java objects to and from JSON.
* *
* <h3>Defining a type's JSON form</h3> * <h3>Defining a type's JSON form</h3>
* By default Gson converts application classes to JSON using its built-in type * 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, * 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 * extend this class to customize the conversion. Here's an example of a type
* adapter for an (X,Y) coordinate point: <pre> {@code * adapter for an (X,Y) coordinate point: <pre> {@code
* *
* public class PointAdapter extends TypeAdapter<Point> { * public class PointAdapter extends TypeAdapter<Point> {
* public Point read(JsonReader reader) throws IOException { * public Point read(JsonReader reader) throws IOException {
* if (reader.peek() == JsonToken.NULL) { * if (reader.peek() == JsonToken.NULL) {
* reader.nextNull(); * reader.nextNull();
* return null; * return null;
* } * }
* String xy = reader.nextString(); * String xy = reader.nextString();
* String[] parts = xy.split(","); * String[] parts = xy.split(",");
* int x = Integer.parseInt(parts[0]); * int x = Integer.parseInt(parts[0]);
* int y = Integer.parseInt(parts[1]); * int y = Integer.parseInt(parts[1]);
* return new Point(x, y); * return new Point(x, y);
* } * }
* public void write(JsonWriter writer, Point value) throws IOException { * public void write(JsonWriter writer, Point value) throws IOException {
* if (value == null) { * if (value == null) {
* writer.nullValue(); * writer.nullValue();
* return; * return;
* } * }
* String xy = value.getX() + "," + value.getY(); * String xy = value.getX() + "," + value.getY();
* writer.value(xy); * writer.value(xy);
* } * }
* }}</pre> * }}</pre>
* With this type adapter installed, Gson will convert {@code Points} to JSON as * 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 * 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. * 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 * <p>The {@link #read(JsonReader) read()} method must read exactly one value
* and {@link #write(JsonWriter,Object) write()} must write 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 * For primitive types this is means readers should make exactly one call to
* {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code * {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code
* nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make * nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make
* exactly one call to one of <code>value()</code> or <code>nullValue()</code>. * 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()}, * For arrays, type adapters should start with a call to {@code beginArray()},
* convert all elements, and finish with a call to {@code endArray()}. For * convert all elements, and finish with a call to {@code endArray()}. For
* objects, they should start with {@code beginObject()}, convert the object, * objects, they should start with {@code beginObject()}, convert the object,
* and finish with {@code endObject()}. Failing to convert a value or converting * and finish with {@code endObject()}. Failing to convert a value or converting
* too many values may cause the application to crash. * too many values may cause the application to crash.
* *
* <p>Type adapters should be prepared to read null from the stream and write it * <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 * to the stream. Alternatively, they should use {@link #nullSafe()} method while
* registering the type adapter with Gson. If your {@code Gson} instance * registering the type adapter with Gson. If your {@code Gson} instance
* has been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be * has been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be
* written to the final document. Otherwise the value (and the corresponding name * 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 * when writing to a JSON object) will be omitted automatically. In either case
* your type adapter must handle null. * your type adapter must handle null.
* *
* <p>To use a custom type adapter with Gson, you must <i>register</i> it with a * <p>To use a custom type adapter with Gson, you must <i>register</i> it with a
* {@link GsonBuilder}: <pre> {@code * {@link GsonBuilder}: <pre> {@code
* *
* GsonBuilder builder = new GsonBuilder(); * GsonBuilder builder = new GsonBuilder();
* builder.registerTypeAdapter(Point.class, new PointAdapter()); * builder.registerTypeAdapter(Point.class, new PointAdapter());
* // if PointAdapter didn't check for nulls in its read/write methods, you should instead use * // if PointAdapter didn't check for nulls in its read/write methods, you should instead use
* // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe()); * // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
* ... * ...
* Gson gson = builder.create(); * Gson gson = builder.create();
* }</pre> * }</pre>
* *
* @since 2.1 * @since 2.1
*/ */
// non-Javadoc: // non-Javadoc:
// //
// <h3>JSON Conversion</h3> // <h3>JSON Conversion</h3>
// <p>A type adapter registered with Gson is automatically invoked while serializing // <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 // or deserializing JSON. However, you can also use type adapters directly to serialize
// and deserialize JSON. Here is an example for deserialization: <pre> {@code // and deserialize JSON. Here is an example for deserialization: <pre> {@code
// //
// String json = "{'origin':'0,0','points':['1,2','3,4']}"; // String json = "{'origin':'0,0','points':['1,2','3,4']}";
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class); // TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
// Graph graph = graphAdapter.fromJson(json); // Graph graph = graphAdapter.fromJson(json);
// }</pre> // }</pre>
// And an example for serialization: <pre> {@code // And an example for serialization: <pre> {@code
// //
// Graph graph = new Graph(...); // Graph graph = new Graph(...);
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class); // TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
// String json = graphAdapter.toJson(graph); // String json = graphAdapter.toJson(graph);
// }</pre> // }</pre>
// //
// <p>Type adapters are <strong>type-specific</strong>. For example, a {@code // <p>Type adapters are <strong>type-specific</strong>. For example, a {@code
// TypeAdapter<Date>} can convert {@code Date} instances to JSON and JSON to // TypeAdapter<Date>} can convert {@code Date} instances to JSON and JSON to
// instances of {@code Date}, but cannot convert any other types. // instances of {@code Date}, but cannot convert any other types.
// //
public abstract class TypeAdapter<T> { public abstract class TypeAdapter<T> {
/** /**
* Writes one JSON value (an array, object, string, number, boolean or null) * Writes one JSON value (an array, object, string, number, boolean or null)
* for {@code value}. * for {@code value}.
* *
* @param value the Java object to write. May be null. * @param value the Java object to write. May be null.
*/ */
public abstract void write(JsonWriter out, T value) throws IOException; public abstract void write(JsonWriter out, T value) throws IOException;
/** /**
* Converts {@code value} to a JSON document and writes it to {@code out}. * Converts {@code value} to a JSON document and writes it to {@code out}.
* Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson} * Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson}
* method, this write is strict. Create a {@link * method, this write is strict. Create a {@link
* JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
* {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient
* writing. * writing.
* *
* @param value the Java object to convert. May be null. * @param value the Java object to convert. May be null.
*/ */
/*public*/ final void toJson(Writer out, T value) throws IOException { /*public*/ final void toJson(Writer out, T value) throws IOException {
JsonWriter writer = new JsonWriter(out); JsonWriter writer = new JsonWriter(out);
write(writer, value); write(writer, value);
} }
/** /**
* This wrapper method is used to make a type adapter null tolerant. In general, a * 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 * type adapter is required to handle nulls in write and read methods. Here is how this
* is typically done:<br> * is typically done:<br>
* <pre> {@code * <pre> {@code
* *
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
* new TypeAdapter<Foo>() { * new TypeAdapter<Foo>() {
* public Foo read(JsonReader in) throws IOException { * public Foo read(JsonReader in) throws IOException {
* if (in.peek() == JsonToken.NULL) { * if (in.peek() == JsonToken.NULL) {
* in.nextNull(); * in.nextNull();
* return null; * return null;
* } * }
* // read a Foo from in and return it * // read a Foo from in and return it
* } * }
* public void write(JsonWriter out, Foo src) throws IOException { * public void write(JsonWriter out, Foo src) throws IOException {
* if (src == null) { * if (src == null) {
* out.nullValue(); * out.nullValue();
* return; * return;
* } * }
* // write src as JSON to out * // write src as JSON to out
* } * }
* }).create(); * }).create();
* }</pre> * }</pre>
* You can avoid this boilerplate handling of nulls by wrapping your type adapter with * 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: * this method. Here is how we will rewrite the above example:
* <pre> {@code * <pre> {@code
* *
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, * Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
* new TypeAdapter<Foo>() { * new TypeAdapter<Foo>() {
* public Foo read(JsonReader in) throws IOException { * public Foo read(JsonReader in) throws IOException {
* // read a Foo from in and return it * // read a Foo from in and return it
* } * }
* public void write(JsonWriter out, Foo src) throws IOException { * public void write(JsonWriter out, Foo src) throws IOException {
* // write src as JSON to out * // write src as JSON to out
* } * }
* }.nullSafe()).create(); * }.nullSafe()).create();
* }</pre> * }</pre>
* Note that we didn't need to check for nulls in our type adapter after we used nullSafe. * Note that we didn't need to check for nulls in our type adapter after we used nullSafe.
*/ */
public final TypeAdapter<T> nullSafe() { public final TypeAdapter<T> nullSafe() {
return new TypeAdapter<T>() { return new TypeAdapter<T>() {
@Override public void write(JsonWriter out, T value) throws IOException { @Override public void write(JsonWriter out, T value) throws IOException {
if (value == null) { if (value == null) {
out.nullValue(); out.nullValue();
} else { } else {
TypeAdapter.this.write(out, value); TypeAdapter.this.write(out, value);
} }
} }
@Override public T read(JsonReader reader) throws IOException { @Override public T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) { if (reader.peek() == JsonToken.NULL) {
reader.nextNull(); reader.nextNull();
return null; return null;
} }
return TypeAdapter.this.read(reader); return TypeAdapter.this.read(reader);
} }
}; };
} }
/** /**
* Converts {@code value} to a JSON document. Unlike Gson's similar {@link * Converts {@code value} to a JSON document. Unlike Gson's similar {@link
* Gson#toJson(Object) toJson} method, this write is strict. Create a {@link * Gson#toJson(Object) toJson} method, this write is strict. Create a {@link
* JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
* {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient * {@link #write(com.google.gson.stream.JsonWriter, Object)} for lenient
* writing. * writing.
* *
* @param value the Java object to convert. May be null. * @param value the Java object to convert. May be null.
*/ */
/*public*/ final String toJson(T value) throws IOException { /*public*/ final String toJson(T value) throws IOException {
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
toJson(stringWriter, value); toJson(stringWriter, value);
return stringWriter.toString(); return stringWriter.toString();
} }
/** /**
* Converts {@code value} to a JSON tree. * Converts {@code value} to a JSON tree.
* *
* @param value the Java object to convert. May be null. * @param value the Java object to convert. May be null.
* @return the converted JSON tree. May be {@link JsonNull}. * @return the converted JSON tree. May be {@link JsonNull}.
*/ */
/*public*/ final JsonElement toJsonTree(T value) { /*public*/ final JsonElement toJsonTree(T value) {
try { try {
JsonTreeWriter jsonWriter = new JsonTreeWriter(); JsonTreeWriter jsonWriter = new JsonTreeWriter();
jsonWriter.setLenient(true); jsonWriter.setLenient(true);
write(jsonWriter, value); write(jsonWriter, value);
return jsonWriter.get(); return jsonWriter.get();
} catch (IOException e) { } catch (IOException e) {
throw new JsonIOException(e); throw new JsonIOException(e);
} }
} }
/** /**
* Reads one JSON value (an array, object, string, number, boolean or null) * Reads one JSON value (an array, object, string, number, boolean or null)
* and converts it to a Java object. Returns the converted object. * and converts it to a Java object. Returns the converted object.
* *
* @return the converted Java object. May be null. * @return the converted Java object. May be null.
*/ */
public abstract T read(JsonReader in) throws IOException; public abstract T read(JsonReader in) throws IOException;
/** /**
* Converts the JSON document in {@code in} to a Java object. Unlike Gson's * 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 * similar {@link Gson#fromJson(java.io.Reader, Class) fromJson} method, this
* read is strict. Create a {@link JsonReader#setLenient(boolean) lenient} * read is strict. Create a {@link JsonReader#setLenient(boolean) lenient}
* {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading. * {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading.
* *
* @return the converted Java object. May be null. * @return the converted Java object. May be null.
*/ */
/*public*/ final T fromJson(Reader in) throws IOException { /*public*/ final T fromJson(Reader in) throws IOException {
JsonReader reader = new JsonReader(in); JsonReader reader = new JsonReader(in);
reader.setLenient(true); // TODO: non-lenient? reader.setLenient(true); // TODO: non-lenient?
return read(reader); return read(reader);
} }
/** /**
* Converts the JSON document in {@code json} to a Java object. Unlike Gson's * 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 * similar {@link Gson#fromJson(String, Class) fromJson} method, this read is
* strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code * strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code
* JsonReader} and call {@link #read(JsonReader)} for lenient reading. * JsonReader} and call {@link #read(JsonReader)} for lenient reading.
* *
* @return the converted Java object. May be null. * @return the converted Java object. May be null.
*/ */
/*public*/ final T fromJson(String json) throws IOException { /*public*/ final T fromJson(String json) throws IOException {
return fromJson(new StringReader(json)); return fromJson(new StringReader(json));
} }
/** /**
* Converts {@code jsonTree} to a Java object. * Converts {@code jsonTree} to a Java object.
* *
* @param jsonTree the Java object to convert. May be {@link JsonNull}. * @param jsonTree the Java object to convert. May be {@link JsonNull}.
*/ */
/*public*/ final T fromJsonTree(JsonElement jsonTree) { /*public*/ final T fromJsonTree(JsonElement jsonTree) {
try { try {
JsonReader jsonReader = new JsonTreeReader(jsonTree); JsonReader jsonReader = new JsonTreeReader(jsonTree);
jsonReader.setLenient(true); jsonReader.setLenient(true);
return read(jsonReader); return read(jsonReader);
} catch (IOException e) { } catch (IOException e) {
throw new JsonIOException(e); throw new JsonIOException(e);
} }
} }
} }
+170 -170
View File
@@ -1,170 +1,170 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
/** /**
* Creates type adapters for set of related types. Type adapter factories are * Creates type adapters for set of related types. Type adapter factories are
* most useful when several types share similar structure in their JSON form. * most useful when several types share similar structure in their JSON form.
* *
* <h3>Example: Converting enums to lowercase</h3> * <h3>Example: Converting enums to lowercase</h3>
* In this example, we implement a factory that creates type adapters for all * 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 * enums. The type adapters will write enums in lowercase, despite the fact
* that they're defined in {@code CONSTANT_CASE} in the corresponding Java * that they're defined in {@code CONSTANT_CASE} in the corresponding Java
* model: <pre> {@code * model: <pre> {@code
* *
* public class LowercaseEnumTypeAdapterFactory implements TypeAdapter.Factory { * public class LowercaseEnumTypeAdapterFactory implements TypeAdapter.Factory {
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { * public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
* Class<T> rawType = (Class<T>) type.getRawType(); * Class<T> rawType = (Class<T>) type.getRawType();
* if (!rawType.isEnum()) { * if (!rawType.isEnum()) {
* return null; * return null;
* } * }
* *
* final Map<String, T> lowercaseToConstant = new HashMap<String, T>(); * final Map<String, T> lowercaseToConstant = new HashMap<String, T>();
* for (T constant : rawType.getEnumConstants()) { * for (T constant : rawType.getEnumConstants()) {
* lowercaseToConstant.put(toLowercase(constant), constant); * lowercaseToConstant.put(toLowercase(constant), constant);
* } * }
* *
* return new TypeAdapter<T>() { * return new TypeAdapter<T>() {
* public void write(JsonWriter out, T value) throws IOException { * public void write(JsonWriter out, T value) throws IOException {
* if (value == null) { * if (value == null) {
* out.nullValue(); * out.nullValue();
* } else { * } else {
* out.value(toLowercase(value)); * out.value(toLowercase(value));
* } * }
* } * }
* *
* public T read(JsonReader reader) throws IOException { * public T read(JsonReader reader) throws IOException {
* if (reader.peek() == JsonToken.NULL) { * if (reader.peek() == JsonToken.NULL) {
* reader.nextNull(); * reader.nextNull();
* return null; * return null;
* } else { * } else {
* return lowercaseToConstant.get(reader.nextString()); * return lowercaseToConstant.get(reader.nextString());
* } * }
* } * }
* }; * };
* } * }
* *
* private String toLowercase(Object o) { * private String toLowercase(Object o) {
* return o.toString().toLowerCase(Locale.US); * return o.toString().toLowerCase(Locale.US);
* } * }
* } * }
* }</pre> * }</pre>
* *
* <p>Type adapter factories select which types they provide type adapters * <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 * 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 * 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 * 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 * most of those types. In the above example the factory returns null for
* calls to {@code create()} where {@code type} is not an enum. * calls to {@code create()} where {@code type} is not an enum.
* *
* <p>A factory is typically called once per type, but the returned type * <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 * 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 * 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 * read()} and {@code write()} methods can be very fast. In this example the
* mapping from lowercase name to enum value is computed eagerly. * mapping from lowercase name to enum value is computed eagerly.
* *
* <p>As with type adapters, factories must be <i>registered</i> with a {@link * <p>As with type adapters, factories must be <i>registered</i> with a {@link
* com.google.gson.GsonBuilder} for them to take effect: <pre> {@code * com.google.gson.GsonBuilder} for them to take effect: <pre> {@code
* *
* GsonBuilder builder = new GsonBuilder(); * GsonBuilder builder = new GsonBuilder();
* builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory()); * builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory());
* ... * ...
* Gson gson = builder.create(); * Gson gson = builder.create();
* }</pre> * }</pre>
* If multiple factories support the same type, the factory registered earlier * If multiple factories support the same type, the factory registered earlier
* takes precedence. * takes precedence.
* *
* <h3>Example: composing other type adapters</h3> * <h3>Example: composing other type adapters</h3>
* In this example we implement a factory for Guava's {@code Multiset} * In this example we implement a factory for Guava's {@code Multiset}
* collection type. The factory can be used to create type adapters for * collection type. The factory can be used to create type adapters for
* multisets of any element type: the type adapter for {@code * multisets of any element type: the type adapter for {@code
* Multiset<String>} is different from the type adapter for {@code * Multiset<String>} is different from the type adapter for {@code
* Multiset<URL>}. * Multiset<URL>}.
* *
* <p>The type adapter <i>delegates</i> to another type adapter for the * <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 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 * multiset's type token. A {@code Gson} is passed in to {@code create} for
* just this purpose: <pre> {@code * just this purpose: <pre> {@code
* *
* public class MultisetTypeAdapterFactory implements TypeAdapter.Factory { * public class MultisetTypeAdapterFactory implements TypeAdapter.Factory {
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { * public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
* Type type = typeToken.getType(); * Type type = typeToken.getType();
* if (typeToken.getRawType() != Multiset.class * if (typeToken.getRawType() != Multiset.class
* || !(type instanceof ParameterizedType)) { * || !(type instanceof ParameterizedType)) {
* return null; * return null;
* } * }
* *
* Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0]; * Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
* TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType)); * TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
* return (TypeAdapter<T>) newMultisetAdapter(elementAdapter); * return (TypeAdapter<T>) newMultisetAdapter(elementAdapter);
* } * }
* *
* private <E> TypeAdapter<Multiset<E>> newMultisetAdapter( * private <E> TypeAdapter<Multiset<E>> newMultisetAdapter(
* final TypeAdapter<E> elementAdapter) { * final TypeAdapter<E> elementAdapter) {
* return new TypeAdapter<Multiset<E>>() { * return new TypeAdapter<Multiset<E>>() {
* public void write(JsonWriter out, Multiset<E> value) throws IOException { * public void write(JsonWriter out, Multiset<E> value) throws IOException {
* if (value == null) { * if (value == null) {
* out.nullValue(); * out.nullValue();
* return; * return;
* } * }
* *
* out.beginArray(); * out.beginArray();
* for (Multiset.Entry<E> entry : value.entrySet()) { * for (Multiset.Entry<E> entry : value.entrySet()) {
* out.value(entry.getCount()); * out.value(entry.getCount());
* elementAdapter.write(out, entry.getElement()); * elementAdapter.write(out, entry.getElement());
* } * }
* out.endArray(); * out.endArray();
* } * }
* *
* public Multiset<E> read(JsonReader in) throws IOException { * public Multiset<E> read(JsonReader in) throws IOException {
* if (in.peek() == JsonToken.NULL) { * if (in.peek() == JsonToken.NULL) {
* in.nextNull(); * in.nextNull();
* return null; * return null;
* } * }
* *
* Multiset<E> result = LinkedHashMultiset.create(); * Multiset<E> result = LinkedHashMultiset.create();
* in.beginArray(); * in.beginArray();
* while (in.hasNext()) { * while (in.hasNext()) {
* int count = in.nextInt(); * int count = in.nextInt();
* E element = elementAdapter.read(in); * E element = elementAdapter.read(in);
* result.add(element, count); * result.add(element, count);
* } * }
* in.endArray(); * in.endArray();
* return result; * return result;
* } * }
* }; * };
* } * }
* } * }
* }</pre> * }</pre>
* Delegating from one type adapter to another is extremely powerful; it's * Delegating from one type adapter to another is extremely powerful; it's
* the foundation of how Gson converts Java objects and collections. Whenever * the foundation of how Gson converts Java objects and collections. Whenever
* possible your factory should retrieve its delegate type adapter in the * possible your factory should retrieve its delegate type adapter in the
* {@code create()} method; this ensures potentially-expensive type adapter * {@code create()} method; this ensures potentially-expensive type adapter
* creation happens only once. * creation happens only once.
* *
* @since 2.1 * @since 2.1
*/ */
public interface TypeAdapterFactory { public interface TypeAdapterFactory {
/** /**
* Returns a type adapter for {@code type}, or null if this factory doesn't * Returns a type adapter for {@code type}, or null if this factory doesn't
* support {@code type}. * support {@code type}.
*/ */
<T> TypeAdapter<T> create(Gson gson, TypeToken<T> type); <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
} }
+79 -79
View File
@@ -1,79 +1,79 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.annotations; package com.google.gson.annotations;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* An annotation that indicates this member should be exposed for JSON * An annotation that indicates this member should be exposed for JSON
* serialization or deserialization. * serialization or deserialization.
* *
* <p>This annotation has no effect unless you build {@link com.google.gson.Gson} * <p>This annotation has no effect unless you build {@link com.google.gson.Gson}
* with a {@link com.google.gson.GsonBuilder} and invoke * with a {@link com.google.gson.GsonBuilder} and invoke
* {@link com.google.gson.GsonBuilder#excludeFieldsWithoutExposeAnnotation()} * {@link com.google.gson.GsonBuilder#excludeFieldsWithoutExposeAnnotation()}
* method.</p> * method.</p>
* *
* <p>Here is an example of how this annotation is meant to be used: * <p>Here is an example of how this annotation is meant to be used:
* <p><pre> * <p><pre>
* public class User { * public class User {
* &#64Expose private String firstName; * &#64Expose private String firstName;
* &#64Expose(serialize = false) private String lastName; * &#64Expose(serialize = false) private String lastName;
* &#64Expose (serialize = false, deserialize = false) private String emailAddress; * &#64Expose (serialize = false, deserialize = false) private String emailAddress;
* private String password; * private String password;
* } * }
* </pre></p> * </pre></p>
* If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()} * If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
* methods will use the {@code password} field along-with {@code firstName}, {@code lastName}, * methods will use the {@code password} field along-with {@code firstName}, {@code lastName},
* and {@code emailAddress} for serialization and deserialization. However, if you created Gson * and {@code emailAddress} for serialization and deserialization. However, if you created Gson
* with {@code Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()} * with {@code Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()}
* then the {@code toJson()} and {@code fromJson()} methods of Gson will exclude the * then the {@code toJson()} and {@code fromJson()} methods of Gson will exclude the
* {@code password} field. This is because the {@code password} field is not marked with the * {@code password} field. This is because the {@code password} field is not marked with the
* {@code @Expose} annotation. Gson will also exclude {@code lastName} and {@code emailAddress} * {@code @Expose} annotation. Gson will also exclude {@code lastName} and {@code emailAddress}
* from serialization since {@code serialize} is set to {@code false}. Similarly, Gson will * from serialization since {@code serialize} is set to {@code false}. Similarly, Gson will
* exclude {@code emailAddress} from deserialization since {@code deserialize} is set to false. * exclude {@code emailAddress} from deserialization since {@code deserialize} is set to false.
* *
* <p>Note that another way to achieve the same effect would have been to just mark the * <p>Note that another way to achieve the same effect would have been to just mark the
* {@code password} field as {@code transient}, and Gson would have excluded it even with default * {@code password} field as {@code transient}, and Gson would have excluded it even with default
* settings. The {@code @Expose} annotation is useful in a style of programming where you want to * settings. The {@code @Expose} annotation is useful in a style of programming where you want to
* explicitly specify all fields that should get considered for serialization or deserialization. * explicitly specify all fields that should get considered for serialization or deserialization.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
public @interface Expose { public @interface Expose {
/** /**
* If {@code true}, the field marked with this annotation is written out in the JSON while * If {@code true}, the field marked with this annotation is written out in the JSON while
* serializing. If {@code false}, the field marked with this annotation is skipped from the * serializing. If {@code false}, the field marked with this annotation is skipped from the
* serialized output. Defaults to {@code true}. * serialized output. Defaults to {@code true}.
* @since 1.4 * @since 1.4
*/ */
public boolean serialize() default true; public boolean serialize() default true;
/** /**
* If {@code true}, the field marked with this annotation is deserialized from the JSON. * If {@code true}, the field marked with this annotation is deserialized from the JSON.
* If {@code false}, the field marked with this annotation is skipped during deserialization. * If {@code false}, the field marked with this annotation is skipped during deserialization.
* Defaults to {@code true}. * Defaults to {@code true}.
* @since 1.4 * @since 1.4
*/ */
public boolean deserialize() default true; public boolean deserialize() default true;
} }
@@ -1,74 +1,74 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.annotations; package com.google.gson.annotations;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* An annotation that indicates this member should be serialized to JSON with * An annotation that indicates this member should be serialized to JSON with
* the provided name value as its field name. * the provided name value as its field name.
* *
* <p>This annotation will override any {@link com.google.gson.FieldNamingPolicy}, including * <p>This annotation will override any {@link com.google.gson.FieldNamingPolicy}, including
* the default field naming policy, that may have been set on the {@link com.google.gson.Gson} * the default field naming policy, that may have been set on the {@link com.google.gson.Gson}
* instance. A different naming policy can set using the {@code GsonBuilder} class. See * instance. A different naming policy can set using the {@code GsonBuilder} class. See
* {@link com.google.gson.GsonBuilder#setFieldNamingPolicy(com.google.gson.FieldNamingPolicy)} * {@link com.google.gson.GsonBuilder#setFieldNamingPolicy(com.google.gson.FieldNamingPolicy)}
* for more information.</p> * for more information.</p>
* *
* <p>Here is an example of how this annotation is meant to be used:</p> * <p>Here is an example of how this annotation is meant to be used:</p>
* <pre> * <pre>
* public class SomeClassWithFields { * public class SomeClassWithFields {
* &#64SerializedName("name") private final String someField; * &#64SerializedName("name") private final String someField;
* private final String someOtherField; * private final String someOtherField;
* *
* public SomeClassWithFields(String a, String b) { * public SomeClassWithFields(String a, String b) {
* this.someField = a; * this.someField = a;
* this.someOtherField = b; * this.someOtherField = b;
* } * }
* } * }
* </pre> * </pre>
* *
* <p>The following shows the output that is generated when serializing an instance of the * <p>The following shows the output that is generated when serializing an instance of the
* above example class:</p> * above example class:</p>
* <pre> * <pre>
* SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b"); * SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b");
* Gson gson = new Gson(); * Gson gson = new Gson();
* String jsonRepresentation = gson.toJson(objectToSerialize); * String jsonRepresentation = gson.toJson(objectToSerialize);
* System.out.println(jsonRepresentation); * System.out.println(jsonRepresentation);
* *
* ===== OUTPUT ===== * ===== OUTPUT =====
* {"name":"a","someOtherField":"b"} * {"name":"a","someOtherField":"b"}
* </pre> * </pre>
* *
* <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p> * <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p>
* *
* @see com.google.gson.FieldNamingPolicy * @see com.google.gson.FieldNamingPolicy
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
public @interface SerializedName { public @interface SerializedName {
/** /**
* @return the desired name of the field when it is serialized * @return the desired name of the field when it is serialized
*/ */
String value(); String value();
} }
+61 -61
View File
@@ -1,61 +1,61 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.annotations; package com.google.gson.annotations;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* An annotation that indicates the version number since a member or a type has been present. * An annotation that indicates the version number since a member or a type has been present.
* This annotation is useful to manage versioning of your Json classes for a web-service. * This annotation is useful to manage versioning of your Json classes for a web-service.
* *
* <p> * <p>
* This annotation has no effect unless you build {@link com.google.gson.Gson} with a * This annotation has no effect unless you build {@link com.google.gson.Gson} with a
* {@link com.google.gson.GsonBuilder} and invoke * {@link com.google.gson.GsonBuilder} and invoke
* {@link com.google.gson.GsonBuilder#setVersion(double)} method. * {@link com.google.gson.GsonBuilder#setVersion(double)} method.
* *
* <p>Here is an example of how this annotation is meant to be used:</p> * <p>Here is an example of how this annotation is meant to be used:</p>
* <pre> * <pre>
* public class User { * public class User {
* private String firstName; * private String firstName;
* private String lastName; * private String lastName;
* &#64Since(1.0) private String emailAddress; * &#64Since(1.0) private String emailAddress;
* &#64Since(1.0) private String password; * &#64Since(1.0) private String password;
* &#64Since(1.1) private Address address; * &#64Since(1.1) private Address address;
* } * }
* </pre> * </pre>
* *
* <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()} * <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
* methods will use all the fields for serialization and deserialization. However, if you created * methods will use all the fields for serialization and deserialization. However, if you created
* Gson with {@code Gson gson = new GsonBuilder().setVersion(1.0).create()} then the * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.0).create()} then the
* {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code address} field * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code address} field
* since it's version number is set to {@code 1.1}.</p> * since it's version number is set to {@code 1.1}.</p>
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE}) @Target({ElementType.FIELD, ElementType.TYPE})
public @interface Since { public @interface Since {
/** /**
* the value indicating a version number since this member * the value indicating a version number since this member
* or type has been present. * or type has been present.
*/ */
double value(); double value();
} }
+66 -66
View File
@@ -1,66 +1,66 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.annotations; package com.google.gson.annotations;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* An annotation that indicates the version number until a member or a type should be present. * An annotation that indicates the version number until a member or a type should be present.
* Basically, if Gson is created with a version number that exceeds the value stored in the * Basically, if Gson is created with a version number that exceeds the value stored in the
* {@code Until} annotation then the field will be ignored from the JSON output. This annotation * {@code Until} annotation then the field will be ignored from the JSON output. This annotation
* is useful to manage versioning of your JSON classes for a web-service. * is useful to manage versioning of your JSON classes for a web-service.
* *
* <p> * <p>
* This annotation has no effect unless you build {@link com.google.gson.Gson} with a * This annotation has no effect unless you build {@link com.google.gson.Gson} with a
* {@link com.google.gson.GsonBuilder} and invoke * {@link com.google.gson.GsonBuilder} and invoke
* {@link com.google.gson.GsonBuilder#setVersion(double)} method. * {@link com.google.gson.GsonBuilder#setVersion(double)} method.
* *
* <p>Here is an example of how this annotation is meant to be used:</p> * <p>Here is an example of how this annotation is meant to be used:</p>
* <pre> * <pre>
* public class User { * public class User {
* private String firstName; * private String firstName;
* private String lastName; * private String lastName;
* &#64Until(1.1) private String emailAddress; * &#64Until(1.1) private String emailAddress;
* &#64Until(1.1) private String password; * &#64Until(1.1) private String password;
* } * }
* </pre> * </pre>
* *
* <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()} * <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
* methods will use all the fields for serialization and deserialization. However, if you created * methods will use all the fields for serialization and deserialization. However, if you created
* Gson with {@code Gson gson = new GsonBuilder().setVersion(1.2).create()} then the * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.2).create()} then the
* {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code emailAddress} * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code emailAddress}
* and {@code password} fields from the example above, because the version number passed to the * and {@code password} fields from the example above, because the version number passed to the
* GsonBuilder, {@code 1.2}, exceeds the version number set on the {@code Until} annotation, * GsonBuilder, {@code 1.2}, exceeds the version number set on the {@code Until} annotation,
* {@code 1.1}, for those fields. * {@code 1.1}, for those fields.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* @since 1.3 * @since 1.3
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE}) @Target({ElementType.FIELD, ElementType.TYPE})
public @interface Until { public @interface Until {
/** /**
* the value indicating a version number until this member * the value indicating a version number until this member
* or type should be ignored. * or type should be ignored.
*/ */
double value(); double value();
} }
@@ -1,6 +1,6 @@
/** /**
* This package provides annotations that can be used with {@link com.google.gson.Gson}. * This package provides annotations that can be used with {@link com.google.gson.Gson}.
* *
* @author Inderjeet Singh, Joel Leitch * @author Inderjeet Singh, Joel Leitch
*/ */
package com.google.gson.annotations; package com.google.gson.annotations;
File diff suppressed because it is too large Load Diff
@@ -1,176 +1,176 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import com.google.gson.InstanceCreator; import com.google.gson.InstanceCreator;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
/** /**
* Returns a function that can construct an instance of a requested type. * Returns a function that can construct an instance of a requested type.
*/ */
public final class ConstructorConstructor { public final class ConstructorConstructor {
private final Map<Type, InstanceCreator<?>> instanceCreators; private final Map<Type, InstanceCreator<?>> instanceCreators;
public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) { public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {
this.instanceCreators = instanceCreators; this.instanceCreators = instanceCreators;
} }
public ConstructorConstructor() { public ConstructorConstructor() {
this(Collections.<Type, InstanceCreator<?>>emptyMap()); this(Collections.<Type, InstanceCreator<?>>emptyMap());
} }
public <T> ObjectConstructor<T> getConstructor(TypeToken<T> typeToken) { public <T> ObjectConstructor<T> getConstructor(TypeToken<T> typeToken) {
final Type type = typeToken.getType(); final Type type = typeToken.getType();
final Class<? super T> rawType = typeToken.getRawType(); final Class<? super T> rawType = typeToken.getRawType();
// first try an instance creator // first try an instance creator
@SuppressWarnings("unchecked") // types must agree @SuppressWarnings("unchecked") // types must agree
final InstanceCreator<T> creator = (InstanceCreator<T>) instanceCreators.get(type); final InstanceCreator<T> creator = (InstanceCreator<T>) instanceCreators.get(type);
if (creator != null) { if (creator != null) {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
public T construct() { public T construct() {
return creator.createInstance(type); return creator.createInstance(type);
} }
}; };
} }
ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType); ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
if (defaultConstructor != null) { if (defaultConstructor != null) {
return defaultConstructor; return defaultConstructor;
} }
ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(rawType); ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(rawType);
if (defaultImplementation != null) { if (defaultImplementation != null) {
return defaultImplementation; return defaultImplementation;
} }
// finally try unsafe // finally try unsafe
return newUnsafeAllocator(type, rawType); return newUnsafeAllocator(type, rawType);
} }
private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) { private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
try { try {
final Constructor<? super T> constructor = rawType.getDeclaredConstructor(); final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
if (!constructor.isAccessible()) { if (!constructor.isAccessible()) {
constructor.setAccessible(true); constructor.setAccessible(true);
} }
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
@SuppressWarnings("unchecked") // T is the same raw type as is requested @SuppressWarnings("unchecked") // T is the same raw type as is requested
public T construct() { public T construct() {
try { try {
Object[] args = null; Object[] args = null;
return (T) constructor.newInstance(args); return (T) constructor.newInstance(args);
} catch (InstantiationException e) { } catch (InstantiationException e) {
// TODO: JsonParseException ? // TODO: JsonParseException ?
throw new RuntimeException("Failed to invoke " + constructor + " with no args", e); throw new RuntimeException("Failed to invoke " + constructor + " with no args", e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
// TODO: don't wrap if cause is unchecked! // TODO: don't wrap if cause is unchecked!
// TODO: JsonParseException ? // TODO: JsonParseException ?
throw new RuntimeException("Failed to invoke " + constructor + " with no args", throw new RuntimeException("Failed to invoke " + constructor + " with no args",
e.getTargetException()); e.getTargetException());
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
}; };
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
return null; return null;
} }
} }
/** /**
* Constructors for common interface types like Map and List and their * Constructors for common interface types like Map and List and their
* subytpes. * subytpes.
*/ */
@SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is @SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is
private <T> ObjectConstructor<T> newDefaultImplementationConstructor(Class<? super T> rawType) { private <T> ObjectConstructor<T> newDefaultImplementationConstructor(Class<? super T> rawType) {
if (Collection.class.isAssignableFrom(rawType)) { if (Collection.class.isAssignableFrom(rawType)) {
if (SortedSet.class.isAssignableFrom(rawType)) { if (SortedSet.class.isAssignableFrom(rawType)) {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
public T construct() { public T construct() {
return (T) new TreeSet<Object>(); return (T) new TreeSet<Object>();
} }
}; };
} else if (Set.class.isAssignableFrom(rawType)) { } else if (Set.class.isAssignableFrom(rawType)) {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
public T construct() { public T construct() {
return (T) new LinkedHashSet<Object>(); return (T) new LinkedHashSet<Object>();
} }
}; };
} else if (Queue.class.isAssignableFrom(rawType)) { } else if (Queue.class.isAssignableFrom(rawType)) {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
public T construct() { public T construct() {
return (T) new LinkedList<Object>(); return (T) new LinkedList<Object>();
} }
}; };
} else { } else {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
public T construct() { public T construct() {
return (T) new ArrayList<Object>(); return (T) new ArrayList<Object>();
} }
}; };
} }
} }
if (Map.class.isAssignableFrom(rawType)) { if (Map.class.isAssignableFrom(rawType)) {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
public T construct() { public T construct() {
return (T) new LinkedHashMap<Object, Object>(); return (T) new LinkedHashMap<Object, Object>();
} }
}; };
// TODO: SortedMap ? // TODO: SortedMap ?
} }
return null; return null;
} }
private <T> ObjectConstructor<T> newUnsafeAllocator( private <T> ObjectConstructor<T> newUnsafeAllocator(
final Type type, final Class<? super T> rawType) { final Type type, final Class<? super T> rawType) {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create(); private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T construct() { public T construct() {
try { try {
Object newInstance = unsafeAllocator.newInstance(rawType); Object newInstance = unsafeAllocator.newInstance(rawType);
return (T) newInstance; return (T) newInstance;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". " throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e); + "Register an InstanceCreator with Gson for this type may fix this problem."), e);
} }
} }
}; };
} }
@Override public String toString() { @Override public String toString() {
return instanceCreators.toString(); return instanceCreators.toString();
} }
} }
+251 -251
View File
@@ -1,251 +1,251 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import com.google.gson.ExclusionStrategy; import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes; import com.google.gson.FieldAttributes;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import com.google.gson.annotations.Since; import com.google.gson.annotations.Since;
import com.google.gson.annotations.Until; import com.google.gson.annotations.Until;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* This class selects which fields and types to omit. It is configurable, * This class selects which fields and types to omit. It is configurable,
* supporting version attributes {@link Since} and {@link Until}, modifiers, * supporting version attributes {@link Since} and {@link Until}, modifiers,
* synthetic fields, anonymous and local classes, inner classes, and fields with * synthetic fields, anonymous and local classes, inner classes, and fields with
* the {@link Expose} annotation. * the {@link Expose} annotation.
* *
* <p>This class is a type adapter factory; types that are excluded will be * <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 * adapted to null. It may delegate to another type adapter if only one
* direction is excluded. * direction is excluded.
* *
* @author Joel Leitch * @author Joel Leitch
* @author Jesse Wilson * @author Jesse Wilson
*/ */
public final class Excluder implements TypeAdapterFactory, Cloneable { public final class Excluder implements TypeAdapterFactory, Cloneable {
private static final double IGNORE_VERSIONS = -1.0d; private static final double IGNORE_VERSIONS = -1.0d;
public static final Excluder DEFAULT = new Excluder(); public static final Excluder DEFAULT = new Excluder();
private double version = IGNORE_VERSIONS; private double version = IGNORE_VERSIONS;
private int modifiers = Modifier.TRANSIENT | Modifier.STATIC; private int modifiers = Modifier.TRANSIENT | Modifier.STATIC;
private boolean serializeInnerClasses = true; private boolean serializeInnerClasses = true;
private boolean requireExpose; private boolean requireExpose;
private List<ExclusionStrategy> serializationStrategies = Collections.emptyList(); private List<ExclusionStrategy> serializationStrategies = Collections.emptyList();
private List<ExclusionStrategy> deserializationStrategies = Collections.emptyList(); private List<ExclusionStrategy> deserializationStrategies = Collections.emptyList();
@Override protected Excluder clone() { @Override protected Excluder clone() {
try { try {
return (Excluder) super.clone(); return (Excluder) super.clone();
} catch (CloneNotSupportedException e) { } catch (CloneNotSupportedException e) {
throw new AssertionError(); throw new AssertionError();
} }
} }
public Excluder withVersion(double ignoreVersionsAfter) { public Excluder withVersion(double ignoreVersionsAfter) {
Excluder result = clone(); Excluder result = clone();
result.version = ignoreVersionsAfter; result.version = ignoreVersionsAfter;
return result; return result;
} }
public Excluder withModifiers(int... modifiers) { public Excluder withModifiers(int... modifiers) {
Excluder result = clone(); Excluder result = clone();
result.modifiers = 0; result.modifiers = 0;
for (int modifier : modifiers) { for (int modifier : modifiers) {
result.modifiers |= modifier; result.modifiers |= modifier;
} }
return result; return result;
} }
public Excluder disableInnerClassSerialization() { public Excluder disableInnerClassSerialization() {
Excluder result = clone(); Excluder result = clone();
result.serializeInnerClasses = false; result.serializeInnerClasses = false;
return result; return result;
} }
public Excluder excludeFieldsWithoutExposeAnnotation() { public Excluder excludeFieldsWithoutExposeAnnotation() {
Excluder result = clone(); Excluder result = clone();
result.requireExpose = true; result.requireExpose = true;
return result; return result;
} }
public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy, public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
boolean serialization, boolean deserialization) { boolean serialization, boolean deserialization) {
Excluder result = clone(); Excluder result = clone();
if (serialization) { if (serialization) {
result.serializationStrategies = new ArrayList<ExclusionStrategy>(serializationStrategies); result.serializationStrategies = new ArrayList<ExclusionStrategy>(serializationStrategies);
result.serializationStrategies.add(exclusionStrategy); result.serializationStrategies.add(exclusionStrategy);
} }
if (deserialization) { if (deserialization) {
result.deserializationStrategies result.deserializationStrategies
= new ArrayList<ExclusionStrategy>(deserializationStrategies); = new ArrayList<ExclusionStrategy>(deserializationStrategies);
result.deserializationStrategies.add(exclusionStrategy); result.deserializationStrategies.add(exclusionStrategy);
} }
return result; return result;
} }
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) { public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
Class<?> rawType = type.getRawType(); Class<?> rawType = type.getRawType();
final boolean skipSerialize = excludeClass(rawType, true); final boolean skipSerialize = excludeClass(rawType, true);
final boolean skipDeserialize = excludeClass(rawType, false); final boolean skipDeserialize = excludeClass(rawType, false);
if (!skipSerialize && !skipDeserialize) { if (!skipSerialize && !skipDeserialize) {
return null; return null;
} }
return new TypeAdapter<T>() { return new TypeAdapter<T>() {
/** The delegate is lazily created because it may not be needed, and creating it may fail. */ /** The delegate is lazily created because it may not be needed, and creating it may fail. */
private TypeAdapter<T> delegate; private TypeAdapter<T> delegate;
@Override public T read(JsonReader in) throws IOException { @Override public T read(JsonReader in) throws IOException {
if (skipDeserialize) { if (skipDeserialize) {
in.skipValue(); in.skipValue();
return null; return null;
} }
return delegate().read(in); return delegate().read(in);
} }
@Override public void write(JsonWriter out, T value) throws IOException { @Override public void write(JsonWriter out, T value) throws IOException {
if (skipSerialize) { if (skipSerialize) {
out.nullValue(); out.nullValue();
return; return;
} }
delegate().write(out, value); delegate().write(out, value);
} }
private TypeAdapter<T> delegate() { private TypeAdapter<T> delegate() {
TypeAdapter<T> d = delegate; TypeAdapter<T> d = delegate;
return d != null return d != null
? d ? d
: (delegate = GsonInternalAccess.INSTANCE.getNextAdapter(gson, Excluder.this, type)); : (delegate = GsonInternalAccess.INSTANCE.getNextAdapter(gson, Excluder.this, type));
} }
}; };
} }
public boolean excludeField(Field field, boolean serialize) { public boolean excludeField(Field field, boolean serialize) {
if ((modifiers & field.getModifiers()) != 0) { if ((modifiers & field.getModifiers()) != 0) {
return true; return true;
} }
if (version != Excluder.IGNORE_VERSIONS if (version != Excluder.IGNORE_VERSIONS
&& !isValidVersion(field.getAnnotation(Since.class), field.getAnnotation(Until.class))) { && !isValidVersion(field.getAnnotation(Since.class), field.getAnnotation(Until.class))) {
return true; return true;
} }
if (field.isSynthetic()) { if (field.isSynthetic()) {
return true; return true;
} }
if (requireExpose) { if (requireExpose) {
Expose annotation = field.getAnnotation(Expose.class); Expose annotation = field.getAnnotation(Expose.class);
if (annotation == null || (serialize ? !annotation.serialize() : !annotation.deserialize())) { if (annotation == null || (serialize ? !annotation.serialize() : !annotation.deserialize())) {
return true; return true;
} }
} }
if (!serializeInnerClasses && isInnerClass(field.getType())) { if (!serializeInnerClasses && isInnerClass(field.getType())) {
return true; return true;
} }
if (isAnonymousOrLocal(field.getType())) { if (isAnonymousOrLocal(field.getType())) {
return true; return true;
} }
List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies; List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
if (!list.isEmpty()) { if (!list.isEmpty()) {
FieldAttributes fieldAttributes = new FieldAttributes(field); FieldAttributes fieldAttributes = new FieldAttributes(field);
for (ExclusionStrategy exclusionStrategy : list) { for (ExclusionStrategy exclusionStrategy : list) {
if (exclusionStrategy.shouldSkipField(fieldAttributes)) { if (exclusionStrategy.shouldSkipField(fieldAttributes)) {
return true; return true;
} }
} }
} }
return false; return false;
} }
public boolean excludeClass(Class<?> clazz, boolean serialize) { public boolean excludeClass(Class<?> clazz, boolean serialize) {
if (version != Excluder.IGNORE_VERSIONS if (version != Excluder.IGNORE_VERSIONS
&& !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) { && !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
return true; return true;
} }
if (!serializeInnerClasses && isInnerClass(clazz)) { if (!serializeInnerClasses && isInnerClass(clazz)) {
return true; return true;
} }
if (isAnonymousOrLocal(clazz)) { if (isAnonymousOrLocal(clazz)) {
return true; return true;
} }
List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies; List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
for (ExclusionStrategy exclusionStrategy : list) { for (ExclusionStrategy exclusionStrategy : list) {
if (exclusionStrategy.shouldSkipClass(clazz)) { if (exclusionStrategy.shouldSkipClass(clazz)) {
return true; return true;
} }
} }
return false; return false;
} }
private boolean isAnonymousOrLocal(Class<?> clazz) { private boolean isAnonymousOrLocal(Class<?> clazz) {
return !Enum.class.isAssignableFrom(clazz) return !Enum.class.isAssignableFrom(clazz)
&& (clazz.isAnonymousClass() || clazz.isLocalClass()); && (clazz.isAnonymousClass() || clazz.isLocalClass());
} }
private boolean isInnerClass(Class<?> clazz) { private boolean isInnerClass(Class<?> clazz) {
return clazz.isMemberClass() && !isStatic(clazz); return clazz.isMemberClass() && !isStatic(clazz);
} }
private boolean isStatic(Class<?> clazz) { private boolean isStatic(Class<?> clazz) {
return (clazz.getModifiers() & Modifier.STATIC) != 0; return (clazz.getModifiers() & Modifier.STATIC) != 0;
} }
private boolean isValidVersion(Since since, Until until) { private boolean isValidVersion(Since since, Until until) {
return isValidSince(since) && isValidUntil(until); return isValidSince(since) && isValidUntil(until);
} }
private boolean isValidSince(Since annotation) { private boolean isValidSince(Since annotation) {
if (annotation != null) { if (annotation != null) {
double annotationVersion = annotation.value(); double annotationVersion = annotation.value();
if (annotationVersion > version) { if (annotationVersion > version) {
return false; return false;
} }
} }
return true; return true;
} }
private boolean isValidUntil(Until annotation) { private boolean isValidUntil(Until annotation) {
if (annotation != null) { if (annotation != null) {
double annotationVersion = annotation.value(); double annotationVersion = annotation.value();
if (annotationVersion <= version) { if (annotationVersion <= version) {
return false; return false;
} }
} }
return true; return true;
} }
} }
@@ -1,39 +1,39 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
/** /**
* Internal-only APIs of Gson available only to other classes in Gson. * Internal-only APIs of Gson available only to other classes in Gson.
*/ */
public abstract class GsonInternalAccess { public abstract class GsonInternalAccess {
public static GsonInternalAccess INSTANCE; public static GsonInternalAccess INSTANCE;
/** /**
* Returns a type adapter for {@code} type that isn't {@code skipPast}. This * 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. * can be used for type adapters to compose other, simpler type adapters.
* *
* @throws IllegalArgumentException if this GSON cannot serialize and * @throws IllegalArgumentException if this GSON cannot serialize and
* deserialize {@code type}. * deserialize {@code type}.
*/ */
public abstract <T> TypeAdapter<T> getNextAdapter( public abstract <T> TypeAdapter<T> getNextAdapter(
Gson gson, TypeAdapterFactory skipPast, TypeToken<T> type); Gson gson, TypeAdapterFactory skipPast, TypeToken<T> type);
} }
@@ -1,32 +1,32 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import java.io.IOException; import java.io.IOException;
/** /**
* Internal-only APIs of JsonReader available only to other classes in Gson. * Internal-only APIs of JsonReader available only to other classes in Gson.
*/ */
public abstract class JsonReaderInternalAccess { public abstract class JsonReaderInternalAccess {
public static JsonReaderInternalAccess INSTANCE; public static JsonReaderInternalAccess INSTANCE;
/** /**
* Changes the type of the current property name token to a string value. * Changes the type of the current property name token to a string value.
*/ */
public abstract void promoteNameToValue(JsonReader reader) throws IOException; public abstract void promoteNameToValue(JsonReader reader) throws IOException;
} }
@@ -1,69 +1,69 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import java.math.BigInteger; import java.math.BigInteger;
/** /**
* This class holds a number value that is lazily converted to a specific number type * This class holds a number value that is lazily converted to a specific number type
* *
* @author Inderjeet Singh * @author Inderjeet Singh
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public final class LazilyParsedNumber extends Number { public final class LazilyParsedNumber extends Number {
private final String value; private final String value;
public LazilyParsedNumber(String value) { public LazilyParsedNumber(String value) {
this.value = value; this.value = value;
} }
@Override @Override
public int intValue() { public int intValue() {
try { try {
return Integer.parseInt(value); return Integer.parseInt(value);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
try { try {
return (int) Long.parseLong(value); return (int) Long.parseLong(value);
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
return new BigInteger(value).intValue(); return new BigInteger(value).intValue();
} }
} }
} }
@Override @Override
public long longValue() { public long longValue() {
try { try {
return Long.parseLong(value); return Long.parseLong(value);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
return new BigInteger(value).longValue(); return new BigInteger(value).longValue();
} }
} }
@Override @Override
public float floatValue() { public float floatValue() {
return Float.parseFloat(value); return Float.parseFloat(value);
} }
@Override @Override
public double doubleValue() { public double doubleValue() {
return Double.parseDouble(value); return Double.parseDouble(value);
} }
@Override @Override
public String toString() { public String toString() {
return value; return value;
} }
} }
@@ -1,33 +1,33 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
/** /**
* Defines a generic object construction factory. The purpose of this class * Defines a generic object construction factory. The purpose of this class
* is to construct a default instance of a class that can be used for object * is to construct a default instance of a class that can be used for object
* navigation while deserialization from its JSON representation. * navigation while deserialization from its JSON representation.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public interface ObjectConstructor<T> { public interface ObjectConstructor<T> {
/** /**
* Returns a new instance. * Returns a new instance.
*/ */
public T construct(); public T construct();
} }
+61 -61
View File
@@ -1,61 +1,61 @@
/* /*
* Copyright (C) 2009 Google Inc. * Copyright (C) 2009 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
/** /**
* A simple object that holds onto a pair of object references, first and second. * A simple object that holds onto a pair of object references, first and second.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* *
* @param <FIRST> * @param <FIRST>
* @param <SECOND> * @param <SECOND>
*/ */
public final class Pair<FIRST, SECOND> { public final class Pair<FIRST, SECOND> {
public final FIRST first; public final FIRST first;
public final SECOND second; public final SECOND second;
public Pair(FIRST first, SECOND second) { public Pair(FIRST first, SECOND second) {
this.first = first; this.first = first;
this.second = second; this.second = second;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return 17 * ((first != null) ? first.hashCode() : 0) return 17 * ((first != null) ? first.hashCode() : 0)
+ 17 * ((second != null) ? second.hashCode() : 0); + 17 * ((second != null) ? second.hashCode() : 0);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (!(o instanceof Pair<?, ?>)) { if (!(o instanceof Pair<?, ?>)) {
return false; return false;
} }
Pair<?, ?> that = (Pair<?, ?>) o; Pair<?, ?> that = (Pair<?, ?>) o;
return equal(this.first, that.first) && equal(this.second, that.second); return equal(this.first, that.first) && equal(this.second, that.second);
} }
private static boolean equal(Object a, Object b) { private static boolean equal(Object a, Object b) {
return a == b || (a != null && a.equals(b)); return a == b || (a != null && a.equals(b));
} }
@Override @Override
public String toString() { public String toString() {
return String.format("{%s,%s}", first, second); return String.format("{%s,%s}", first, second);
} }
} }
+118 -118
View File
@@ -1,118 +1,118 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.$Gson$Preconditions;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Contains static utility methods pertaining to primitive types and their * Contains static utility methods pertaining to primitive types and their
* corresponding wrapper types. * corresponding wrapper types.
* *
* @author Kevin Bourrillion * @author Kevin Bourrillion
*/ */
public final class Primitives { public final class Primitives {
private Primitives() {} private Primitives() {}
/** A map from primitive types to their corresponding wrapper types. */ /** A map from primitive types to their corresponding wrapper types. */
private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE; private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE;
/** A map from wrapper types to their corresponding primitive types. */ /** A map from wrapper types to their corresponding primitive types. */
private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE; private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE;
// Sad that we can't use a BiMap. :( // Sad that we can't use a BiMap. :(
static { static {
Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16); Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16);
Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16); Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16);
add(primToWrap, wrapToPrim, boolean.class, Boolean.class); add(primToWrap, wrapToPrim, boolean.class, Boolean.class);
add(primToWrap, wrapToPrim, byte.class, Byte.class); add(primToWrap, wrapToPrim, byte.class, Byte.class);
add(primToWrap, wrapToPrim, char.class, Character.class); add(primToWrap, wrapToPrim, char.class, Character.class);
add(primToWrap, wrapToPrim, double.class, Double.class); add(primToWrap, wrapToPrim, double.class, Double.class);
add(primToWrap, wrapToPrim, float.class, Float.class); add(primToWrap, wrapToPrim, float.class, Float.class);
add(primToWrap, wrapToPrim, int.class, Integer.class); add(primToWrap, wrapToPrim, int.class, Integer.class);
add(primToWrap, wrapToPrim, long.class, Long.class); add(primToWrap, wrapToPrim, long.class, Long.class);
add(primToWrap, wrapToPrim, short.class, Short.class); add(primToWrap, wrapToPrim, short.class, Short.class);
add(primToWrap, wrapToPrim, void.class, Void.class); add(primToWrap, wrapToPrim, void.class, Void.class);
PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap); PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap);
WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim); WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim);
} }
private static void add(Map<Class<?>, Class<?>> forward, private static void add(Map<Class<?>, Class<?>> forward,
Map<Class<?>, Class<?>> backward, Class<?> key, Class<?> value) { Map<Class<?>, Class<?>> backward, Class<?> key, Class<?> value) {
forward.put(key, value); forward.put(key, value);
backward.put(value, key); backward.put(value, key);
} }
/** /**
* Returns true if this type is a primitive. * Returns true if this type is a primitive.
*/ */
public static boolean isPrimitive(Type type) { public static boolean isPrimitive(Type type) {
return PRIMITIVE_TO_WRAPPER_TYPE.containsKey(type); return PRIMITIVE_TO_WRAPPER_TYPE.containsKey(type);
} }
/** /**
* Returns {@code true} if {@code type} is one of the nine * Returns {@code true} if {@code type} is one of the nine
* primitive-wrapper types, such as {@link Integer}. * primitive-wrapper types, such as {@link Integer}.
* *
* @see Class#isPrimitive * @see Class#isPrimitive
*/ */
public static boolean isWrapperType(Type type) { public static boolean isWrapperType(Type type) {
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey( return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(
$Gson$Preconditions.checkNotNull(type)); $Gson$Preconditions.checkNotNull(type));
} }
/** /**
* Returns the corresponding wrapper type of {@code type} if it is a primitive * Returns the corresponding wrapper type of {@code type} if it is a primitive
* type; otherwise returns {@code type} itself. Idempotent. * type; otherwise returns {@code type} itself. Idempotent.
* <pre> * <pre>
* wrap(int.class) == Integer.class * wrap(int.class) == Integer.class
* wrap(Integer.class) == Integer.class * wrap(Integer.class) == Integer.class
* wrap(String.class) == String.class * wrap(String.class) == String.class
* </pre> * </pre>
*/ */
public static <T> Class<T> wrap(Class<T> type) { public static <T> Class<T> wrap(Class<T> type) {
// cast is safe: long.class and Long.class are both of type Class<Long> // cast is safe: long.class and Long.class are both of type Class<Long>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<T> wrapped = (Class<T>) PRIMITIVE_TO_WRAPPER_TYPE.get( Class<T> wrapped = (Class<T>) PRIMITIVE_TO_WRAPPER_TYPE.get(
$Gson$Preconditions.checkNotNull(type)); $Gson$Preconditions.checkNotNull(type));
return (wrapped == null) ? type : wrapped; return (wrapped == null) ? type : wrapped;
} }
/** /**
* Returns the corresponding primitive type of {@code type} if it is a * Returns the corresponding primitive type of {@code type} if it is a
* wrapper type; otherwise returns {@code type} itself. Idempotent. * wrapper type; otherwise returns {@code type} itself. Idempotent.
* <pre> * <pre>
* unwrap(Integer.class) == int.class * unwrap(Integer.class) == int.class
* unwrap(int.class) == int.class * unwrap(int.class) == int.class
* unwrap(String.class) == String.class * unwrap(String.class) == String.class
* </pre> * </pre>
*/ */
public static <T> Class<T> unwrap(Class<T> type) { public static <T> Class<T> unwrap(Class<T> type) {
// cast is safe: long.class and Long.class are both of type Class<Long> // cast is safe: long.class and Long.class are both of type Class<Long>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get( Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get(
$Gson$Preconditions.checkNotNull(type)); $Gson$Preconditions.checkNotNull(type));
return (unwrapped == null) ? type : unwrapped; return (unwrapped == null) ? type : unwrapped;
} }
} }
+115 -115
View File
@@ -1,115 +1,115 @@
/* /*
* Copyright (C) 2010 Google Inc. * Copyright (C) 2010 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonIOException; import com.google.gson.JsonIOException;
import com.google.gson.JsonNull; import com.google.gson.JsonNull;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.internal.bind.TypeAdapters; import com.google.gson.internal.bind.TypeAdapters;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.MalformedJsonException; import com.google.gson.stream.MalformedJsonException;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
/** /**
* Reads and writes GSON parse trees over streams. * Reads and writes GSON parse trees over streams.
*/ */
public final class Streams { public final class Streams {
/** /**
* Takes a reader in any state and returns the next value as a JsonElement. * Takes a reader in any state and returns the next value as a JsonElement.
*/ */
public static JsonElement parse(JsonReader reader) throws JsonParseException { public static JsonElement parse(JsonReader reader) throws JsonParseException {
boolean isEmpty = true; boolean isEmpty = true;
try { try {
reader.peek(); reader.peek();
isEmpty = false; isEmpty = false;
return TypeAdapters.JSON_ELEMENT.read(reader); return TypeAdapters.JSON_ELEMENT.read(reader);
} catch (EOFException e) { } catch (EOFException e) {
/* /*
* For compatibility with JSON 1.5 and earlier, we return a JsonNull for * For compatibility with JSON 1.5 and earlier, we return a JsonNull for
* empty documents instead of throwing. * empty documents instead of throwing.
*/ */
if (isEmpty) { if (isEmpty) {
return JsonNull.INSTANCE; return JsonNull.INSTANCE;
} }
throw new JsonIOException(e); throw new JsonIOException(e);
} catch (MalformedJsonException e) { } catch (MalformedJsonException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} catch (IOException e) { } catch (IOException e) {
throw new JsonIOException(e); throw new JsonIOException(e);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} }
} }
/** /**
* Writes the JSON element to the writer, recursively. * Writes the JSON element to the writer, recursively.
*/ */
public static void write(JsonElement element, JsonWriter writer) throws IOException { public static void write(JsonElement element, JsonWriter writer) throws IOException {
TypeAdapters.JSON_ELEMENT.write(writer, element); TypeAdapters.JSON_ELEMENT.write(writer, element);
} }
public static Writer writerForAppendable(Appendable appendable) { public static Writer writerForAppendable(Appendable appendable) {
return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable); return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable);
} }
/** /**
* Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer} * Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer}
* is used. * is used.
*/ */
private static class AppendableWriter extends Writer { private static class AppendableWriter extends Writer {
private final Appendable appendable; private final Appendable appendable;
private final CurrentWrite currentWrite = new CurrentWrite(); private final CurrentWrite currentWrite = new CurrentWrite();
private AppendableWriter(Appendable appendable) { private AppendableWriter(Appendable appendable) {
this.appendable = appendable; this.appendable = appendable;
} }
@Override public void write(char[] chars, int offset, int length) throws IOException { @Override public void write(char[] chars, int offset, int length) throws IOException {
currentWrite.chars = chars; currentWrite.chars = chars;
appendable.append(currentWrite, offset, offset + length); appendable.append(currentWrite, offset, offset + length);
} }
@Override public void write(int i) throws IOException { @Override public void write(int i) throws IOException {
appendable.append((char) i); appendable.append((char) i);
} }
@Override public void flush() {} @Override public void flush() {}
@Override public void close() {} @Override public void close() {}
/** /**
* A mutable char sequence pointing at a single char[]. * A mutable char sequence pointing at a single char[].
*/ */
static class CurrentWrite implements CharSequence { static class CurrentWrite implements CharSequence {
char[] chars; char[] chars;
public int length() { public int length() {
return chars.length; return chars.length;
} }
public char charAt(int i) { public char charAt(int i) {
return chars[i]; return chars[i];
} }
public CharSequence subSequence(int start, int end) { public CharSequence subSequence(int start, int end) {
return new String(chars, start, end - start); return new String(chars, start, end - start);
} }
} }
} }
} }
+104 -104
View File
@@ -1,104 +1,104 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal; package com.google.gson.internal;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectStreamClass; import java.io.ObjectStreamClass;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
/** /**
* Do sneaky things to allocate objects without invoking their constructors. * Do sneaky things to allocate objects without invoking their constructors.
* *
* @author Joel Leitch * @author Joel Leitch
* @author Jesse Wilson * @author Jesse Wilson
*/ */
public abstract class UnsafeAllocator { public abstract class UnsafeAllocator {
public abstract <T> T newInstance(Class<T> c) throws Exception; public abstract <T> T newInstance(Class<T> c) throws Exception;
public static UnsafeAllocator create() { public static UnsafeAllocator create() {
// try JVM // try JVM
// public class Unsafe { // public class Unsafe {
// public Object allocateInstance(Class<?> type); // public Object allocateInstance(Class<?> type);
// } // }
try { try {
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe"); Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field f = unsafeClass.getDeclaredField("theUnsafe"); Field f = unsafeClass.getDeclaredField("theUnsafe");
f.setAccessible(true); f.setAccessible(true);
final Object unsafe = f.get(null); final Object unsafe = f.get(null);
final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class); final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
return new UnsafeAllocator() { return new UnsafeAllocator() {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T newInstance(Class<T> c) throws Exception { public <T> T newInstance(Class<T> c) throws Exception {
return (T) allocateInstance.invoke(unsafe, c); return (T) allocateInstance.invoke(unsafe, c);
} }
}; };
} catch (Exception ignored) { } catch (Exception ignored) {
} }
// try dalvikvm, pre-gingerbread // try dalvikvm, pre-gingerbread
// public class ObjectInputStream { // public class ObjectInputStream {
// private static native Object newInstance( // private static native Object newInstance(
// Class<?> instantiationClass, Class<?> constructorClass); // Class<?> instantiationClass, Class<?> constructorClass);
// } // }
try { try {
final Method newInstance = ObjectInputStream.class final Method newInstance = ObjectInputStream.class
.getDeclaredMethod("newInstance", Class.class, Class.class); .getDeclaredMethod("newInstance", Class.class, Class.class);
newInstance.setAccessible(true); newInstance.setAccessible(true);
return new UnsafeAllocator() { return new UnsafeAllocator() {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T newInstance(Class<T> c) throws Exception { public <T> T newInstance(Class<T> c) throws Exception {
return (T) newInstance.invoke(null, c, Object.class); return (T) newInstance.invoke(null, c, Object.class);
} }
}; };
} catch (Exception ignored) { } catch (Exception ignored) {
} }
// try dalvikvm, post-gingerbread // try dalvikvm, post-gingerbread
// public class ObjectStreamClass { // public class ObjectStreamClass {
// private static native int getConstructorId(Class<?> c); // private static native int getConstructorId(Class<?> c);
// private static native Object newInstance(Class<?> instantiationClass, int methodId); // private static native Object newInstance(Class<?> instantiationClass, int methodId);
// } // }
try { try {
Method getConstructorId = ObjectStreamClass.class Method getConstructorId = ObjectStreamClass.class
.getDeclaredMethod("getConstructorId", Class.class); .getDeclaredMethod("getConstructorId", Class.class);
getConstructorId.setAccessible(true); getConstructorId.setAccessible(true);
final int constructorId = (Integer) getConstructorId.invoke(null, Object.class); final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
final Method newInstance = ObjectStreamClass.class final Method newInstance = ObjectStreamClass.class
.getDeclaredMethod("newInstance", Class.class, int.class); .getDeclaredMethod("newInstance", Class.class, int.class);
newInstance.setAccessible(true); newInstance.setAccessible(true);
return new UnsafeAllocator() { return new UnsafeAllocator() {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T newInstance(Class<T> c) throws Exception { public <T> T newInstance(Class<T> c) throws Exception {
return (T) newInstance.invoke(null, c, constructorId); return (T) newInstance.invoke(null, c, constructorId);
} }
}; };
} catch (Exception ignored) { } catch (Exception ignored) {
} }
// give up // give up
return new UnsafeAllocator() { return new UnsafeAllocator() {
@Override @Override
public <T> T newInstance(Class<T> c) { public <T> T newInstance(Class<T> c) {
throw new UnsupportedOperationException("Cannot allocate " + c); throw new UnsupportedOperationException("Cannot allocate " + c);
} }
}; };
} }
} }
@@ -1,97 +1,97 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Types;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
/** /**
* Adapt an array of objects. * Adapt an array of objects.
*/ */
public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> { public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType(); Type type = typeToken.getType();
if (!(type instanceof GenericArrayType || type instanceof Class && ((Class<?>) type).isArray())) { if (!(type instanceof GenericArrayType || type instanceof Class && ((Class<?>) type).isArray())) {
return null; return null;
} }
Type componentType = $Gson$Types.getArrayComponentType(type); Type componentType = $Gson$Types.getArrayComponentType(type);
TypeAdapter<?> componentTypeAdapter = gson.getAdapter(TypeToken.get(componentType)); TypeAdapter<?> componentTypeAdapter = gson.getAdapter(TypeToken.get(componentType));
return new ArrayTypeAdapter( return new ArrayTypeAdapter(
gson, componentTypeAdapter, $Gson$Types.getRawType(componentType)); gson, componentTypeAdapter, $Gson$Types.getRawType(componentType));
} }
}; };
private final Class<E> componentType; private final Class<E> componentType;
private final TypeAdapter<E> componentTypeAdapter; private final TypeAdapter<E> componentTypeAdapter;
public ArrayTypeAdapter(Gson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) { public ArrayTypeAdapter(Gson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) {
this.componentTypeAdapter = this.componentTypeAdapter =
new TypeAdapterRuntimeTypeWrapper<E>(context, componentTypeAdapter, componentType); new TypeAdapterRuntimeTypeWrapper<E>(context, componentTypeAdapter, componentType);
this.componentType = componentType; this.componentType = componentType;
} }
public Object read(JsonReader in) throws IOException { public Object read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
List<E> list = new ArrayList<E>(); List<E> list = new ArrayList<E>();
in.beginArray(); in.beginArray();
while (in.hasNext()) { while (in.hasNext()) {
E instance = componentTypeAdapter.read(in); E instance = componentTypeAdapter.read(in);
list.add(instance); list.add(instance);
} }
in.endArray(); in.endArray();
Object array = Array.newInstance(componentType, list.size()); Object array = Array.newInstance(componentType, list.size());
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
Array.set(array, i, list.get(i)); Array.set(array, i, list.get(i));
} }
return array; return array;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override public void write(JsonWriter out, Object array) throws IOException { @Override public void write(JsonWriter out, Object array) throws IOException {
if (array == null) { if (array == null) {
out.nullValue(); out.nullValue();
return; return;
} }
out.beginArray(); out.beginArray();
for (int i = 0, length = Array.getLength(array); i < length; i++) { for (int i = 0, length = Array.getLength(array); i < length; i++) {
E value = (E) Array.get(array, i); E value = (E) Array.get(array, i);
componentTypeAdapter.write(out, value); componentTypeAdapter.write(out, value);
} }
out.endArray(); out.endArray();
} }
} }
@@ -1,52 +1,52 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* Adapts a BigDecimal type to and from its JSON representation. * Adapts a BigDecimal type to and from its JSON representation.
* *
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal> { public final class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal> {
@Override @Override
public BigDecimal read(JsonReader in) throws IOException { public BigDecimal read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
try { try {
return new BigDecimal(in.nextString()); return new BigDecimal(in.nextString());
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} }
} }
@Override @Override
public void write(JsonWriter out, BigDecimal value) throws IOException { public void write(JsonWriter out, BigDecimal value) throws IOException {
out.value(value); out.value(value);
} }
} }
@@ -1,51 +1,51 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
/** /**
* Adapts a BigInteger type to and from its JSON representation. * Adapts a BigInteger type to and from its JSON representation.
* *
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class BigIntegerTypeAdapter extends TypeAdapter<BigInteger> { public final class BigIntegerTypeAdapter extends TypeAdapter<BigInteger> {
@Override @Override
public BigInteger read(JsonReader in) throws IOException { public BigInteger read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
try { try {
return new BigInteger(in.nextString()); return new BigInteger(in.nextString());
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} }
} }
@Override @Override
public void write(JsonWriter out, BigInteger value) throws IOException { public void write(JsonWriter out, BigInteger value) throws IOException {
out.value(value); out.value(value);
} }
} }
@@ -1,101 +1,101 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Types;
import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.ConstructorConstructor;
import com.google.gson.internal.ObjectConstructor; import com.google.gson.internal.ObjectConstructor;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
/** /**
* Adapt a homogeneous collection of objects. * Adapt a homogeneous collection of objects.
*/ */
public final class CollectionTypeAdapterFactory implements TypeAdapterFactory { public final class CollectionTypeAdapterFactory implements TypeAdapterFactory {
private final ConstructorConstructor constructorConstructor; private final ConstructorConstructor constructorConstructor;
public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) { public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
this.constructorConstructor = constructorConstructor; this.constructorConstructor = constructorConstructor;
} }
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType(); Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType(); Class<? super T> rawType = typeToken.getRawType();
if (!Collection.class.isAssignableFrom(rawType)) { if (!Collection.class.isAssignableFrom(rawType)) {
return null; return null;
} }
Type elementType = $Gson$Types.getCollectionElementType(type, rawType); Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType)); TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken); ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
@SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter @SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter
TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor); TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);
return result; return result;
} }
private final class Adapter<E> extends TypeAdapter<Collection<E>> { private final class Adapter<E> extends TypeAdapter<Collection<E>> {
private final TypeAdapter<E> elementTypeAdapter; private final TypeAdapter<E> elementTypeAdapter;
private final ObjectConstructor<? extends Collection<E>> constructor; private final ObjectConstructor<? extends Collection<E>> constructor;
public Adapter(Gson context, Type elementType, public Adapter(Gson context, Type elementType,
TypeAdapter<E> elementTypeAdapter, TypeAdapter<E> elementTypeAdapter,
ObjectConstructor<? extends Collection<E>> constructor) { ObjectConstructor<? extends Collection<E>> constructor) {
this.elementTypeAdapter = this.elementTypeAdapter =
new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType); new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);
this.constructor = constructor; this.constructor = constructor;
} }
public Collection<E> read(JsonReader in) throws IOException { public Collection<E> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
Collection<E> collection = constructor.construct(); Collection<E> collection = constructor.construct();
in.beginArray(); in.beginArray();
while (in.hasNext()) { while (in.hasNext()) {
E instance = elementTypeAdapter.read(in); E instance = elementTypeAdapter.read(in);
collection.add(instance); collection.add(instance);
} }
in.endArray(); in.endArray();
return collection; return collection;
} }
public void write(JsonWriter out, Collection<E> collection) throws IOException { public void write(JsonWriter out, Collection<E> collection) throws IOException {
if (collection == null) { if (collection == null) {
out.nullValue(); // TODO: better policy here? out.nullValue(); // TODO: better policy here?
return; return;
} }
out.beginArray(); out.beginArray();
for (E element : collection) { for (E element : collection) {
elementTypeAdapter.write(out, element); elementTypeAdapter.write(out, element);
} }
out.endArray(); out.endArray();
} }
} }
} }
@@ -1,93 +1,93 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
/** /**
* Adapter for Date. Although this class appears stateless, it is not. * Adapter for Date. Although this class appears stateless, it is not.
* DateFormat captures its time zone and locale when it is created, which gives * DateFormat captures its time zone and locale when it is created, which gives
* this class state. DateFormat isn't thread safe either, so this class has * this class state. DateFormat isn't thread safe either, so this class has
* to synchronize its read and write methods. * to synchronize its read and write methods.
*/ */
public final class DateTypeAdapter extends TypeAdapter<Date> { public final class DateTypeAdapter extends TypeAdapter<Date> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) new DateTypeAdapter() : null; return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) new DateTypeAdapter() : null;
} }
}; };
private final DateFormat enUsFormat private final DateFormat enUsFormat
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US); = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US);
private final DateFormat localFormat private final DateFormat localFormat
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT); = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
private final DateFormat iso8601Format = buildIso8601Format(); private final DateFormat iso8601Format = buildIso8601Format();
private static DateFormat buildIso8601Format() { private static DateFormat buildIso8601Format() {
DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
return iso8601Format; return iso8601Format;
} }
@Override public Date read(JsonReader in) throws IOException { @Override public Date read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
return deserializeToDate(in.nextString()); return deserializeToDate(in.nextString());
} }
private synchronized Date deserializeToDate(String json) { private synchronized Date deserializeToDate(String json) {
try { try {
return localFormat.parse(json); return localFormat.parse(json);
} catch (ParseException ignored) { } catch (ParseException ignored) {
} }
try { try {
return enUsFormat.parse(json); return enUsFormat.parse(json);
} catch (ParseException ignored) { } catch (ParseException ignored) {
} }
try { try {
return iso8601Format.parse(json); return iso8601Format.parse(json);
} catch (ParseException e) { } catch (ParseException e) {
throw new JsonSyntaxException(json, e); throw new JsonSyntaxException(json, e);
} }
} }
@Override public synchronized void write(JsonWriter out, Date value) throws IOException { @Override public synchronized void write(JsonWriter out, Date value) throws IOException {
if (value == null) { if (value == null) {
out.nullValue(); out.nullValue();
return; return;
} }
String dateFormatAsString = enUsFormat.format(value); String dateFormatAsString = enUsFormat.format(value);
out.value(dateFormatAsString); out.value(dateFormatAsString);
} }
} }
@@ -1,226 +1,226 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonNull; import com.google.gson.JsonNull;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* This reader walks the elements of a JsonElement as if it was coming from a * This reader walks the elements of a JsonElement as if it was coming from a
* character stream. * character stream.
* *
* @author Jesse Wilson * @author Jesse Wilson
*/ */
public final class JsonTreeReader extends JsonReader { public final class JsonTreeReader extends JsonReader {
private static final Reader UNREADABLE_READER = new Reader() { private static final Reader UNREADABLE_READER = new Reader() {
@Override public int read(char[] buffer, int offset, int count) throws IOException { @Override public int read(char[] buffer, int offset, int count) throws IOException {
throw new AssertionError(); throw new AssertionError();
} }
@Override public void close() throws IOException { @Override public void close() throws IOException {
throw new AssertionError(); throw new AssertionError();
} }
}; };
private static final Object SENTINEL_CLOSED = new Object(); private static final Object SENTINEL_CLOSED = new Object();
private final List<Object> stack = new ArrayList<Object>(); private final List<Object> stack = new ArrayList<Object>();
public JsonTreeReader(JsonElement element) { public JsonTreeReader(JsonElement element) {
super(UNREADABLE_READER); super(UNREADABLE_READER);
stack.add(element); stack.add(element);
} }
@Override public void beginArray() throws IOException { @Override public void beginArray() throws IOException {
expect(JsonToken.BEGIN_ARRAY); expect(JsonToken.BEGIN_ARRAY);
JsonArray array = (JsonArray) peekStack(); JsonArray array = (JsonArray) peekStack();
stack.add(array.iterator()); stack.add(array.iterator());
} }
@Override public void endArray() throws IOException { @Override public void endArray() throws IOException {
expect(JsonToken.END_ARRAY); expect(JsonToken.END_ARRAY);
popStack(); // empty iterator popStack(); // empty iterator
popStack(); // array popStack(); // array
} }
@Override public void beginObject() throws IOException { @Override public void beginObject() throws IOException {
expect(JsonToken.BEGIN_OBJECT); expect(JsonToken.BEGIN_OBJECT);
JsonObject object = (JsonObject) peekStack(); JsonObject object = (JsonObject) peekStack();
stack.add(object.entrySet().iterator()); stack.add(object.entrySet().iterator());
} }
@Override public void endObject() throws IOException { @Override public void endObject() throws IOException {
expect(JsonToken.END_OBJECT); expect(JsonToken.END_OBJECT);
popStack(); // empty iterator popStack(); // empty iterator
popStack(); // object popStack(); // object
} }
@Override public boolean hasNext() throws IOException { @Override public boolean hasNext() throws IOException {
JsonToken token = peek(); JsonToken token = peek();
return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY; return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
} }
@Override public JsonToken peek() throws IOException { @Override public JsonToken peek() throws IOException {
if (stack.isEmpty()) { if (stack.isEmpty()) {
return JsonToken.END_DOCUMENT; return JsonToken.END_DOCUMENT;
} }
Object o = peekStack(); Object o = peekStack();
if (o instanceof Iterator) { if (o instanceof Iterator) {
boolean isObject = stack.get(stack.size() - 2) instanceof JsonObject; boolean isObject = stack.get(stack.size() - 2) instanceof JsonObject;
Iterator<?> iterator = (Iterator<?>) o; Iterator<?> iterator = (Iterator<?>) o;
if (iterator.hasNext()) { if (iterator.hasNext()) {
if (isObject) { if (isObject) {
return JsonToken.NAME; return JsonToken.NAME;
} else { } else {
stack.add(iterator.next()); stack.add(iterator.next());
return peek(); return peek();
} }
} else { } else {
return isObject ? JsonToken.END_OBJECT : JsonToken.END_ARRAY; return isObject ? JsonToken.END_OBJECT : JsonToken.END_ARRAY;
} }
} else if (o instanceof JsonObject) { } else if (o instanceof JsonObject) {
return JsonToken.BEGIN_OBJECT; return JsonToken.BEGIN_OBJECT;
} else if (o instanceof JsonArray) { } else if (o instanceof JsonArray) {
return JsonToken.BEGIN_ARRAY; return JsonToken.BEGIN_ARRAY;
} else if (o instanceof JsonPrimitive) { } else if (o instanceof JsonPrimitive) {
JsonPrimitive primitive = (JsonPrimitive) o; JsonPrimitive primitive = (JsonPrimitive) o;
if (primitive.isString()) { if (primitive.isString()) {
return JsonToken.STRING; return JsonToken.STRING;
} else if (primitive.isBoolean()) { } else if (primitive.isBoolean()) {
return JsonToken.BOOLEAN; return JsonToken.BOOLEAN;
} else if (primitive.isNumber()) { } else if (primitive.isNumber()) {
return JsonToken.NUMBER; return JsonToken.NUMBER;
} else { } else {
throw new AssertionError(); throw new AssertionError();
} }
} else if (o instanceof JsonNull) { } else if (o instanceof JsonNull) {
return JsonToken.NULL; return JsonToken.NULL;
} else if (o == SENTINEL_CLOSED) { } else if (o == SENTINEL_CLOSED) {
throw new IllegalStateException("JsonReader is closed"); throw new IllegalStateException("JsonReader is closed");
} else { } else {
throw new AssertionError(); throw new AssertionError();
} }
} }
private Object peekStack() { private Object peekStack() {
return stack.get(stack.size() - 1); return stack.get(stack.size() - 1);
} }
private Object popStack() { private Object popStack() {
return stack.remove(stack.size() - 1); return stack.remove(stack.size() - 1);
} }
private void expect(JsonToken expected) throws IOException { private void expect(JsonToken expected) throws IOException {
if (peek() != expected) { if (peek() != expected) {
throw new IllegalStateException("Expected " + expected + " but was " + peek()); throw new IllegalStateException("Expected " + expected + " but was " + peek());
} }
} }
@Override public String nextName() throws IOException { @Override public String nextName() throws IOException {
expect(JsonToken.NAME); expect(JsonToken.NAME);
Iterator<?> i = (Iterator<?>) peekStack(); Iterator<?> i = (Iterator<?>) peekStack();
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next(); Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();
stack.add(entry.getValue()); stack.add(entry.getValue());
return (String) entry.getKey(); return (String) entry.getKey();
} }
@Override public String nextString() throws IOException { @Override public String nextString() throws IOException {
JsonToken token = peek(); JsonToken token = peek();
if (token != JsonToken.STRING && token != JsonToken.NUMBER) { if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
throw new IllegalStateException("Expected " + JsonToken.STRING + " but was " + token); throw new IllegalStateException("Expected " + JsonToken.STRING + " but was " + token);
} }
return ((JsonPrimitive) popStack()).getAsString(); return ((JsonPrimitive) popStack()).getAsString();
} }
@Override public boolean nextBoolean() throws IOException { @Override public boolean nextBoolean() throws IOException {
expect(JsonToken.BOOLEAN); expect(JsonToken.BOOLEAN);
return ((JsonPrimitive) popStack()).getAsBoolean(); return ((JsonPrimitive) popStack()).getAsBoolean();
} }
@Override public void nextNull() throws IOException { @Override public void nextNull() throws IOException {
expect(JsonToken.NULL); expect(JsonToken.NULL);
popStack(); popStack();
} }
@Override public double nextDouble() throws IOException { @Override public double nextDouble() throws IOException {
JsonToken token = peek(); JsonToken token = peek();
if (token != JsonToken.NUMBER && token != JsonToken.STRING) { if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token); throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
} }
double result = ((JsonPrimitive) peekStack()).getAsDouble(); double result = ((JsonPrimitive) peekStack()).getAsDouble();
if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) { if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) {
throw new NumberFormatException("JSON forbids NaN and infinities: " + result); throw new NumberFormatException("JSON forbids NaN and infinities: " + result);
} }
popStack(); popStack();
return result; return result;
} }
@Override public long nextLong() throws IOException { @Override public long nextLong() throws IOException {
JsonToken token = peek(); JsonToken token = peek();
if (token != JsonToken.NUMBER && token != JsonToken.STRING) { if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token); throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
} }
long result = ((JsonPrimitive) peekStack()).getAsLong(); long result = ((JsonPrimitive) peekStack()).getAsLong();
popStack(); popStack();
return result; return result;
} }
@Override public int nextInt() throws IOException { @Override public int nextInt() throws IOException {
JsonToken token = peek(); JsonToken token = peek();
if (token != JsonToken.NUMBER && token != JsonToken.STRING) { if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token); throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
} }
int result = ((JsonPrimitive) peekStack()).getAsInt(); int result = ((JsonPrimitive) peekStack()).getAsInt();
popStack(); popStack();
return result; return result;
} }
@Override public void close() throws IOException { @Override public void close() throws IOException {
stack.clear(); stack.clear();
stack.add(SENTINEL_CLOSED); stack.add(SENTINEL_CLOSED);
} }
@Override public void skipValue() throws IOException { @Override public void skipValue() throws IOException {
if (peek() == JsonToken.NAME) { if (peek() == JsonToken.NAME) {
nextName(); nextName();
} else { } else {
popStack(); popStack();
} }
} }
@Override public String toString() { @Override public String toString() {
return getClass().getSimpleName(); return getClass().getSimpleName();
} }
public void promoteNameToValue() throws IOException { public void promoteNameToValue() throws IOException {
expect(JsonToken.NAME); expect(JsonToken.NAME);
Iterator<?> i = (Iterator<?>) peekStack(); Iterator<?> i = (Iterator<?>) peekStack();
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next(); Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();
stack.add(entry.getValue()); stack.add(entry.getValue());
stack.add(new JsonPrimitive((String)entry.getKey())); stack.add(new JsonPrimitive((String)entry.getKey()));
} }
} }
@@ -1,200 +1,200 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonNull; import com.google.gson.JsonNull;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* This writer creates a JsonElement. * This writer creates a JsonElement.
*/ */
public final class JsonTreeWriter extends JsonWriter { public final class JsonTreeWriter extends JsonWriter {
private static final Writer UNWRITABLE_WRITER = new Writer() { private static final Writer UNWRITABLE_WRITER = new Writer() {
@Override public void write(char[] buffer, int offset, int counter) { @Override public void write(char[] buffer, int offset, int counter) {
throw new AssertionError(); throw new AssertionError();
} }
@Override public void flush() throws IOException { @Override public void flush() throws IOException {
throw new AssertionError(); throw new AssertionError();
} }
@Override public void close() throws IOException { @Override public void close() throws IOException {
throw new AssertionError(); throw new AssertionError();
} }
}; };
/** Added to the top of the stack when this writer is closed to cause following ops to fail. */ /** Added to the top of the stack when this writer is closed to cause following ops to fail. */
private static final JsonPrimitive SENTINEL_CLOSED = new JsonPrimitive("closed"); private static final JsonPrimitive SENTINEL_CLOSED = new JsonPrimitive("closed");
/** The JsonElements and JsonArrays under modification, outermost to innermost. */ /** The JsonElements and JsonArrays under modification, outermost to innermost. */
private final List<JsonElement> stack = new ArrayList<JsonElement>(); private final List<JsonElement> stack = new ArrayList<JsonElement>();
/** The name for the next JSON object value. If non-null, the top of the stack is a JsonObject. */ /** The name for the next JSON object value. If non-null, the top of the stack is a JsonObject. */
private String pendingName; private String pendingName;
/** the JSON element constructed by this writer. */ /** the JSON element constructed by this writer. */
private JsonElement product = JsonNull.INSTANCE; // TODO: is this really what we want?; private JsonElement product = JsonNull.INSTANCE; // TODO: is this really what we want?;
public JsonTreeWriter() { public JsonTreeWriter() {
super(UNWRITABLE_WRITER); super(UNWRITABLE_WRITER);
} }
/** /**
* Returns the top level object produced by this writer. * Returns the top level object produced by this writer.
*/ */
public JsonElement get() { public JsonElement get() {
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
throw new IllegalStateException("Expected one JSON element but was " + stack); throw new IllegalStateException("Expected one JSON element but was " + stack);
} }
return product; return product;
} }
private JsonElement peek() { private JsonElement peek() {
return stack.get(stack.size() - 1); return stack.get(stack.size() - 1);
} }
private void put(JsonElement value) { private void put(JsonElement value) {
if (pendingName != null) { if (pendingName != null) {
if (!value.isJsonNull() || getSerializeNulls()) { if (!value.isJsonNull() || getSerializeNulls()) {
JsonObject object = (JsonObject) peek(); JsonObject object = (JsonObject) peek();
object.add(pendingName, value); object.add(pendingName, value);
} }
pendingName = null; pendingName = null;
} else if (stack.isEmpty()) { } else if (stack.isEmpty()) {
product = value; product = value;
} else { } else {
JsonElement element = peek(); JsonElement element = peek();
if (element instanceof JsonArray) { if (element instanceof JsonArray) {
((JsonArray) element).add(value); ((JsonArray) element).add(value);
} else { } else {
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
} }
@Override public JsonWriter beginArray() throws IOException { @Override public JsonWriter beginArray() throws IOException {
JsonArray array = new JsonArray(); JsonArray array = new JsonArray();
put(array); put(array);
stack.add(array); stack.add(array);
return this; return this;
} }
@Override public JsonWriter endArray() throws IOException { @Override public JsonWriter endArray() throws IOException {
if (stack.isEmpty() || pendingName != null) { if (stack.isEmpty() || pendingName != null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
JsonElement element = peek(); JsonElement element = peek();
if (element instanceof JsonArray) { if (element instanceof JsonArray) {
stack.remove(stack.size() - 1); stack.remove(stack.size() - 1);
return this; return this;
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
@Override public JsonWriter beginObject() throws IOException { @Override public JsonWriter beginObject() throws IOException {
JsonObject object = new JsonObject(); JsonObject object = new JsonObject();
put(object); put(object);
stack.add(object); stack.add(object);
return this; return this;
} }
@Override public JsonWriter endObject() throws IOException { @Override public JsonWriter endObject() throws IOException {
if (stack.isEmpty() || pendingName != null) { if (stack.isEmpty() || pendingName != null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
JsonElement element = peek(); JsonElement element = peek();
if (element instanceof JsonObject) { if (element instanceof JsonObject) {
stack.remove(stack.size() - 1); stack.remove(stack.size() - 1);
return this; return this;
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
@Override public JsonWriter name(String name) throws IOException { @Override public JsonWriter name(String name) throws IOException {
if (stack.isEmpty() || pendingName != null) { if (stack.isEmpty() || pendingName != null) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
JsonElement element = peek(); JsonElement element = peek();
if (element instanceof JsonObject) { if (element instanceof JsonObject) {
pendingName = name; pendingName = name;
return this; return this;
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
@Override public JsonWriter value(String value) throws IOException { @Override public JsonWriter value(String value) throws IOException {
if (value == null) { if (value == null) {
return nullValue(); return nullValue();
} }
put(new JsonPrimitive(value)); put(new JsonPrimitive(value));
return this; return this;
} }
@Override public JsonWriter nullValue() throws IOException { @Override public JsonWriter nullValue() throws IOException {
put(JsonNull.INSTANCE); put(JsonNull.INSTANCE);
return this; return this;
} }
@Override public JsonWriter value(boolean value) throws IOException { @Override public JsonWriter value(boolean value) throws IOException {
put(new JsonPrimitive(value)); put(new JsonPrimitive(value));
return this; return this;
} }
@Override public JsonWriter value(double value) throws IOException { @Override public JsonWriter value(double value) throws IOException {
if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) { if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) {
throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value); throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value);
} }
put(new JsonPrimitive(value)); put(new JsonPrimitive(value));
return this; return this;
} }
@Override public JsonWriter value(long value) throws IOException { @Override public JsonWriter value(long value) throws IOException {
put(new JsonPrimitive(value)); put(new JsonPrimitive(value));
return this; return this;
} }
@Override public JsonWriter value(Number value) throws IOException { @Override public JsonWriter value(Number value) throws IOException {
if (value == null) { if (value == null) {
return nullValue(); return nullValue();
} }
if (!isLenient()) { if (!isLenient()) {
double d = value.doubleValue(); double d = value.doubleValue();
if (Double.isNaN(d) || Double.isInfinite(d)) { if (Double.isNaN(d) || Double.isInfinite(d)) {
throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value); throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value);
} }
} }
put(new JsonPrimitive(value)); put(new JsonPrimitive(value));
return this; return this;
} }
@Override public void flush() throws IOException { @Override public void flush() throws IOException {
} }
@Override public void close() throws IOException { @Override public void close() throws IOException {
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
throw new IOException("Incomplete document"); throw new IOException("Incomplete document");
} }
stack.add(SENTINEL_CLOSED); stack.add(SENTINEL_CLOSED);
} }
} }
@@ -1,277 +1,277 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonIOException; import com.google.gson.JsonIOException;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Types;
import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.ConstructorConstructor;
import com.google.gson.internal.JsonReaderInternalAccess; import com.google.gson.internal.JsonReaderInternalAccess;
import com.google.gson.internal.ObjectConstructor; import com.google.gson.internal.ObjectConstructor;
import com.google.gson.internal.Streams; import com.google.gson.internal.Streams;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Adapts maps to either JSON objects or JSON arrays. * Adapts maps to either JSON objects or JSON arrays.
* *
* <h3>Maps as JSON objects</h3> * <h3>Maps as JSON objects</h3>
* For primitive keys or when complex map key serialization is not enabled, this * For primitive keys or when complex map key serialization is not enabled, this
* converts Java {@link Map Maps} to JSON Objects. This requires that map keys * converts Java {@link Map Maps} to JSON Objects. This requires that map keys
* can be serialized as strings; this is insufficient for some key types. For * can be serialized as strings; this is insufficient for some key types. For
* example, consider a map whose keys are points on a grid. The default JSON * example, consider a map whose keys are points on a grid. The default JSON
* form encodes reasonably: <pre> {@code * form encodes reasonably: <pre> {@code
* Map<Point, String> original = new LinkedHashMap<Point, String>(); * Map<Point, String> original = new LinkedHashMap<Point, String>();
* original.put(new Point(5, 6), "a"); * original.put(new Point(5, 6), "a");
* original.put(new Point(8, 8), "b"); * original.put(new Point(8, 8), "b");
* System.out.println(gson.toJson(original, type)); * System.out.println(gson.toJson(original, type));
* }</pre> * }</pre>
* The above code prints this JSON object:<pre> {@code * The above code prints this JSON object:<pre> {@code
* { * {
* "(5,6)": "a", * "(5,6)": "a",
* "(8,8)": "b" * "(8,8)": "b"
* } * }
* }</pre> * }</pre>
* But GSON is unable to deserialize this value because the JSON string name is * 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 * just the {@link Object#toString() toString()} of the map key. Attempting to
* convert the above JSON to an object fails with a parse exception: * convert the above JSON to an object fails with a parse exception:
* <pre>com.google.gson.JsonParseException: Expecting object found: "(5,6)" * <pre>com.google.gson.JsonParseException: Expecting object found: "(5,6)"
* at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler * at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
* at com.google.gson.ObjectNavigator.navigateClassFields * at com.google.gson.ObjectNavigator.navigateClassFields
* ...</pre> * ...</pre>
* *
* <h3>Maps as JSON arrays</h3> * <h3>Maps as JSON arrays</h3>
* An alternative approach taken by this type adapter when it is required and * An alternative approach taken by this type adapter when it is required and
* complex map key serialization is enabled is to encode maps as arrays of map * complex map key serialization is enabled is to encode maps as arrays of map
* entries. Each map entry is a two element array containing a key and a value. * entries. Each map entry is a two element array containing a key and a value.
* This approach is more flexible because any type can be used as the map's key; * This approach is more flexible because any type can be used as the map's key;
* not just strings. But it's also less portable because the receiver of such * not just strings. But it's also less portable because the receiver of such
* JSON must be aware of the map entry convention. * JSON must be aware of the map entry convention.
* *
* <p>Register this adapter when you are creating your GSON instance. * <p>Register this adapter when you are creating your GSON instance.
* <pre> {@code * <pre> {@code
* Gson gson = new GsonBuilder() * Gson gson = new GsonBuilder()
* .registerTypeAdapter(Map.class, new MapAsArrayTypeAdapter()) * .registerTypeAdapter(Map.class, new MapAsArrayTypeAdapter())
* .create(); * .create();
* }</pre> * }</pre>
* This will change the structure of the JSON emitted by the code above. Now we * This will change the structure of the JSON emitted by the code above. Now we
* get an array. In this case the arrays elements are map entries: * get an array. In this case the arrays elements are map entries:
* <pre> {@code * <pre> {@code
* [ * [
* [ * [
* { * {
* "x": 5, * "x": 5,
* "y": 6 * "y": 6
* }, * },
* "a", * "a",
* ], * ],
* [ * [
* { * {
* "x": 8, * "x": 8,
* "y": 8 * "y": 8
* }, * },
* "b" * "b"
* ] * ]
* ] * ]
* }</pre> * }</pre>
* This format will serialize and deserialize just fine as long as this adapter * This format will serialize and deserialize just fine as long as this adapter
* is registered. * is registered.
*/ */
public final class MapTypeAdapterFactory implements TypeAdapterFactory { public final class MapTypeAdapterFactory implements TypeAdapterFactory {
private final ConstructorConstructor constructorConstructor; private final ConstructorConstructor constructorConstructor;
private final boolean complexMapKeySerialization; private final boolean complexMapKeySerialization;
public MapTypeAdapterFactory(ConstructorConstructor constructorConstructor, public MapTypeAdapterFactory(ConstructorConstructor constructorConstructor,
boolean complexMapKeySerialization) { boolean complexMapKeySerialization) {
this.constructorConstructor = constructorConstructor; this.constructorConstructor = constructorConstructor;
this.complexMapKeySerialization = complexMapKeySerialization; this.complexMapKeySerialization = complexMapKeySerialization;
} }
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType(); Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType(); Class<? super T> rawType = typeToken.getRawType();
if (!Map.class.isAssignableFrom(rawType)) { if (!Map.class.isAssignableFrom(rawType)) {
return null; return null;
} }
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type); Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc); Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc);
TypeAdapter<?> keyAdapter = getKeyAdapter(gson, keyAndValueTypes[0]); TypeAdapter<?> keyAdapter = getKeyAdapter(gson, keyAndValueTypes[0]);
TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(keyAndValueTypes[1])); TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(keyAndValueTypes[1]));
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken); ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
// we don't define a type parameter for the key or value types // we don't define a type parameter for the key or value types
TypeAdapter<T> result = new Adapter(gson, keyAndValueTypes[0], keyAdapter, TypeAdapter<T> result = new Adapter(gson, keyAndValueTypes[0], keyAdapter,
keyAndValueTypes[1], valueAdapter, constructor); keyAndValueTypes[1], valueAdapter, constructor);
return result; return result;
} }
/** /**
* Returns a type adapter that writes the value as a string. * Returns a type adapter that writes the value as a string.
*/ */
private TypeAdapter<?> getKeyAdapter(Gson context, Type keyType) { private TypeAdapter<?> getKeyAdapter(Gson context, Type keyType) {
return (keyType == boolean.class || keyType == Boolean.class) return (keyType == boolean.class || keyType == Boolean.class)
? TypeAdapters.BOOLEAN_AS_STRING ? TypeAdapters.BOOLEAN_AS_STRING
: context.getAdapter(TypeToken.get(keyType)); : context.getAdapter(TypeToken.get(keyType));
} }
private final class Adapter<K, V> extends TypeAdapter<Map<K, V>> { private final class Adapter<K, V> extends TypeAdapter<Map<K, V>> {
private final TypeAdapter<K> keyTypeAdapter; private final TypeAdapter<K> keyTypeAdapter;
private final TypeAdapter<V> valueTypeAdapter; private final TypeAdapter<V> valueTypeAdapter;
private final ObjectConstructor<? extends Map<K, V>> constructor; private final ObjectConstructor<? extends Map<K, V>> constructor;
public Adapter(Gson context, Type keyType, TypeAdapter<K> keyTypeAdapter, public Adapter(Gson context, Type keyType, TypeAdapter<K> keyTypeAdapter,
Type valueType, TypeAdapter<V> valueTypeAdapter, Type valueType, TypeAdapter<V> valueTypeAdapter,
ObjectConstructor<? extends Map<K, V>> constructor) { ObjectConstructor<? extends Map<K, V>> constructor) {
this.keyTypeAdapter = this.keyTypeAdapter =
new TypeAdapterRuntimeTypeWrapper<K>(context, keyTypeAdapter, keyType); new TypeAdapterRuntimeTypeWrapper<K>(context, keyTypeAdapter, keyType);
this.valueTypeAdapter = this.valueTypeAdapter =
new TypeAdapterRuntimeTypeWrapper<V>(context, valueTypeAdapter, valueType); new TypeAdapterRuntimeTypeWrapper<V>(context, valueTypeAdapter, valueType);
this.constructor = constructor; this.constructor = constructor;
} }
public Map<K, V> read(JsonReader in) throws IOException { public Map<K, V> read(JsonReader in) throws IOException {
JsonToken peek = in.peek(); JsonToken peek = in.peek();
if (peek == JsonToken.NULL) { if (peek == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
Map<K, V> map = constructor.construct(); Map<K, V> map = constructor.construct();
if (peek == JsonToken.BEGIN_ARRAY) { if (peek == JsonToken.BEGIN_ARRAY) {
in.beginArray(); in.beginArray();
while (in.hasNext()) { while (in.hasNext()) {
in.beginArray(); // entry array in.beginArray(); // entry array
K key = keyTypeAdapter.read(in); K key = keyTypeAdapter.read(in);
V value = valueTypeAdapter.read(in); V value = valueTypeAdapter.read(in);
V replaced = map.put(key, value); V replaced = map.put(key, value);
if (replaced != null) { if (replaced != null) {
throw new JsonSyntaxException("duplicate key: " + key); throw new JsonSyntaxException("duplicate key: " + key);
} }
in.endArray(); in.endArray();
} }
in.endArray(); in.endArray();
} else { } else {
in.beginObject(); in.beginObject();
while (in.hasNext()) { while (in.hasNext()) {
JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in); JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);
K key = keyTypeAdapter.read(in); K key = keyTypeAdapter.read(in);
V value = valueTypeAdapter.read(in); V value = valueTypeAdapter.read(in);
V replaced = map.put(key, value); V replaced = map.put(key, value);
if (replaced != null) { if (replaced != null) {
throw new JsonSyntaxException("duplicate key: " + key); throw new JsonSyntaxException("duplicate key: " + key);
} }
} }
in.endObject(); in.endObject();
} }
return map; return map;
} }
public void write(JsonWriter out, Map<K, V> map) throws IOException { public void write(JsonWriter out, Map<K, V> map) throws IOException {
if (map == null) { if (map == null) {
out.nullValue(); out.nullValue();
return; return;
} }
if (!complexMapKeySerialization) { if (!complexMapKeySerialization) {
out.beginObject(); out.beginObject();
for (Map.Entry<K, V> entry : map.entrySet()) { for (Map.Entry<K, V> entry : map.entrySet()) {
out.name(String.valueOf(entry.getKey())); out.name(String.valueOf(entry.getKey()));
valueTypeAdapter.write(out, entry.getValue()); valueTypeAdapter.write(out, entry.getValue());
} }
out.endObject(); out.endObject();
return; return;
} }
boolean hasComplexKeys = false; boolean hasComplexKeys = false;
List<JsonElement> keys = new ArrayList<JsonElement>(map.size()); List<JsonElement> keys = new ArrayList<JsonElement>(map.size());
List<V> values = new ArrayList<V>(map.size()); List<V> values = new ArrayList<V>(map.size());
for (Map.Entry<K, V> entry : map.entrySet()) { for (Map.Entry<K, V> entry : map.entrySet()) {
JsonElement keyElement = toJsonTree(keyTypeAdapter, entry.getKey()); JsonElement keyElement = toJsonTree(keyTypeAdapter, entry.getKey());
keys.add(keyElement); keys.add(keyElement);
values.add(entry.getValue()); values.add(entry.getValue());
hasComplexKeys |= keyElement.isJsonArray() || keyElement.isJsonObject(); hasComplexKeys |= keyElement.isJsonArray() || keyElement.isJsonObject();
} }
if (hasComplexKeys) { if (hasComplexKeys) {
out.beginArray(); out.beginArray();
for (int i = 0; i < keys.size(); i++) { for (int i = 0; i < keys.size(); i++) {
out.beginArray(); // entry array out.beginArray(); // entry array
Streams.write(keys.get(i), out); Streams.write(keys.get(i), out);
valueTypeAdapter.write(out, values.get(i)); valueTypeAdapter.write(out, values.get(i));
out.endArray(); out.endArray();
} }
out.endArray(); out.endArray();
} else { } else {
out.beginObject(); out.beginObject();
for (int i = 0; i < keys.size(); i++) { for (int i = 0; i < keys.size(); i++) {
JsonElement keyElement = keys.get(i); JsonElement keyElement = keys.get(i);
out.name(keyToString(keyElement)); out.name(keyToString(keyElement));
valueTypeAdapter.write(out, values.get(i)); valueTypeAdapter.write(out, values.get(i));
} }
out.endObject(); out.endObject();
} }
} }
private String keyToString(JsonElement keyElement) { private String keyToString(JsonElement keyElement) {
if (keyElement.isJsonPrimitive()) { if (keyElement.isJsonPrimitive()) {
JsonPrimitive primitive = keyElement.getAsJsonPrimitive(); JsonPrimitive primitive = keyElement.getAsJsonPrimitive();
if (primitive.isNumber()) { if (primitive.isNumber()) {
return String.valueOf(primitive.getAsNumber()); return String.valueOf(primitive.getAsNumber());
} else if (primitive.isBoolean()) { } else if (primitive.isBoolean()) {
return Boolean.toString(primitive.getAsBoolean()); return Boolean.toString(primitive.getAsBoolean());
} else if (primitive.isString()) { } else if (primitive.isString()) {
return primitive.getAsString(); return primitive.getAsString();
} else { } else {
throw new AssertionError(); throw new AssertionError();
} }
} else if (keyElement.isJsonNull()) { } else if (keyElement.isJsonNull()) {
return "null"; return "null";
} else { } else {
throw new AssertionError(); throw new AssertionError();
} }
} }
} }
// TODO: remove this when TypeAdapter.toJsonTree() is public // TODO: remove this when TypeAdapter.toJsonTree() is public
private static <T> JsonElement toJsonTree(TypeAdapter<T> typeAdapter, T value) { private static <T> JsonElement toJsonTree(TypeAdapter<T> typeAdapter, T value) {
try { try {
JsonTreeWriter jsonWriter = new JsonTreeWriter(); JsonTreeWriter jsonWriter = new JsonTreeWriter();
jsonWriter.setLenient(true); jsonWriter.setLenient(true);
typeAdapter.write(jsonWriter, value); typeAdapter.write(jsonWriter, value);
return jsonWriter.get(); return jsonWriter.get();
} catch (IOException e) { } catch (IOException e) {
throw new JsonIOException(e); throw new JsonIOException(e);
} }
} }
} }
@@ -1,107 +1,107 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Adapts types whose static type is only 'Object'. Uses getClass() on * Adapts types whose static type is only 'Object'. Uses getClass() on
* serialization and a primitive/Map/List on deserialization. * serialization and a primitive/Map/List on deserialization.
*/ */
public final class ObjectTypeAdapter extends TypeAdapter<Object> { public final class ObjectTypeAdapter extends TypeAdapter<Object> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (type.getRawType() == Object.class) { if (type.getRawType() == Object.class) {
return (TypeAdapter<T>) new ObjectTypeAdapter(gson); return (TypeAdapter<T>) new ObjectTypeAdapter(gson);
} }
return null; return null;
} }
}; };
private final Gson gson; private final Gson gson;
private ObjectTypeAdapter(Gson gson) { private ObjectTypeAdapter(Gson gson) {
this.gson = gson; this.gson = gson;
} }
@Override public Object read(JsonReader in) throws IOException { @Override public Object read(JsonReader in) throws IOException {
JsonToken token = in.peek(); JsonToken token = in.peek();
switch (token) { switch (token) {
case BEGIN_ARRAY: case BEGIN_ARRAY:
List<Object> list = new ArrayList<Object>(); List<Object> list = new ArrayList<Object>();
in.beginArray(); in.beginArray();
while (in.hasNext()) { while (in.hasNext()) {
list.add(read(in)); list.add(read(in));
} }
in.endArray(); in.endArray();
return list; return list;
case BEGIN_OBJECT: case BEGIN_OBJECT:
Map<String, Object> map = new LinkedHashMap<String, Object>(); Map<String, Object> map = new LinkedHashMap<String, Object>();
in.beginObject(); in.beginObject();
while (in.hasNext()) { while (in.hasNext()) {
map.put(in.nextName(), read(in)); map.put(in.nextName(), read(in));
} }
in.endObject(); in.endObject();
return map; return map;
case STRING: case STRING:
return in.nextString(); return in.nextString();
case NUMBER: case NUMBER:
return in.nextDouble(); return in.nextDouble();
case BOOLEAN: case BOOLEAN:
return in.nextBoolean(); return in.nextBoolean();
case NULL: case NULL:
in.nextNull(); in.nextNull();
return null; return null;
} }
throw new IllegalStateException(); throw new IllegalStateException();
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override public void write(JsonWriter out, Object value) throws IOException { @Override public void write(JsonWriter out, Object value) throws IOException {
if (value == null) { if (value == null) {
out.nullValue(); out.nullValue();
return; return;
} }
TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass()); TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass());
if (typeAdapter instanceof ObjectTypeAdapter) { if (typeAdapter instanceof ObjectTypeAdapter) {
out.beginObject(); out.beginObject();
out.endObject(); out.endObject();
return; return;
} }
typeAdapter.write(out, value); typeAdapter.write(out, value);
} }
} }
@@ -1,209 +1,209 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.FieldNamingStrategy; import com.google.gson.FieldNamingStrategy;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Types;
import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.ConstructorConstructor;
import com.google.gson.internal.Excluder; import com.google.gson.internal.Excluder;
import com.google.gson.internal.ObjectConstructor; import com.google.gson.internal.ObjectConstructor;
import com.google.gson.internal.Primitives; import com.google.gson.internal.Primitives;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
* Type adapter that reflects over the fields and methods of a class. * Type adapter that reflects over the fields and methods of a class.
*/ */
public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
private final ConstructorConstructor constructorConstructor; private final ConstructorConstructor constructorConstructor;
private final FieldNamingStrategy fieldNamingPolicy; private final FieldNamingStrategy fieldNamingPolicy;
private final Excluder excluder; private final Excluder excluder;
public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor, public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor,
FieldNamingStrategy fieldNamingPolicy, Excluder excluder) { FieldNamingStrategy fieldNamingPolicy, Excluder excluder) {
this.constructorConstructor = constructorConstructor; this.constructorConstructor = constructorConstructor;
this.fieldNamingPolicy = fieldNamingPolicy; this.fieldNamingPolicy = fieldNamingPolicy;
this.excluder = excluder; this.excluder = excluder;
} }
public boolean excludeField(Field f, boolean serialize) { public boolean excludeField(Field f, boolean serialize) {
return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize); return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize);
} }
private String getFieldName(Field f) { private String getFieldName(Field f) {
SerializedName serializedName = f.getAnnotation(SerializedName.class); SerializedName serializedName = f.getAnnotation(SerializedName.class);
return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value(); return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value();
} }
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) { public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
Class<? super T> raw = type.getRawType(); Class<? super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) { if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive! return null; // it's a primitive!
} }
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(type); ObjectConstructor<T> constructor = constructorConstructor.getConstructor(type);
return new Adapter<T>(constructor, getBoundFields(gson, type, raw)); return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
} }
private ReflectiveTypeAdapterFactory.BoundField createBoundField( private ReflectiveTypeAdapterFactory.BoundField createBoundField(
final Gson context, final Field field, final String name, final Gson context, final Field field, final String name,
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) { final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType()); final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
// special casing primitives here saves ~5% on Android... // special casing primitives here saves ~5% on Android...
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) { return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType); final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
@SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree @SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
@Override void write(JsonWriter writer, Object value) @Override void write(JsonWriter writer, Object value)
throws IOException, IllegalAccessException { throws IOException, IllegalAccessException {
Object fieldValue = field.get(value); Object fieldValue = field.get(value);
TypeAdapter t = TypeAdapter t =
new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType()); new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType());
t.write(writer, fieldValue); t.write(writer, fieldValue);
} }
@Override void read(JsonReader reader, Object value) @Override void read(JsonReader reader, Object value)
throws IOException, IllegalAccessException { throws IOException, IllegalAccessException {
Object fieldValue = typeAdapter.read(reader); Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null || !isPrimitive) { if (fieldValue != null || !isPrimitive) {
field.set(value, fieldValue); field.set(value, fieldValue);
} }
} }
}; };
} }
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) { private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>(); Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
if (raw.isInterface()) { if (raw.isInterface()) {
return result; return result;
} }
Type declaredType = type.getType(); Type declaredType = type.getType();
while (raw != Object.class) { while (raw != Object.class) {
Field[] fields = raw.getDeclaredFields(); Field[] fields = raw.getDeclaredFields();
for (Field field : fields) { for (Field field : fields) {
boolean serialize = excludeField(field, true); boolean serialize = excludeField(field, true);
boolean deserialize = excludeField(field, false); boolean deserialize = excludeField(field, false);
if (!serialize && !deserialize) { if (!serialize && !deserialize) {
continue; continue;
} }
field.setAccessible(true); field.setAccessible(true);
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType()); Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
BoundField boundField = createBoundField(context, field, getFieldName(field), BoundField boundField = createBoundField(context, field, getFieldName(field),
TypeToken.get(fieldType), serialize, deserialize); TypeToken.get(fieldType), serialize, deserialize);
BoundField previous = result.put(boundField.name, boundField); BoundField previous = result.put(boundField.name, boundField);
if (previous != null) { if (previous != null) {
throw new IllegalArgumentException(declaredType throw new IllegalArgumentException(declaredType
+ " declares multiple JSON fields named " + previous.name); + " declares multiple JSON fields named " + previous.name);
} }
} }
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass())); type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
raw = type.getRawType(); raw = type.getRawType();
} }
return result; return result;
} }
static abstract class BoundField { static abstract class BoundField {
final String name; final String name;
final boolean serialized; final boolean serialized;
final boolean deserialized; final boolean deserialized;
protected BoundField(String name, boolean serialized, boolean deserialized) { protected BoundField(String name, boolean serialized, boolean deserialized) {
this.name = name; this.name = name;
this.serialized = serialized; this.serialized = serialized;
this.deserialized = deserialized; this.deserialized = deserialized;
} }
abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException; abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException; abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
} }
public final class Adapter<T> extends TypeAdapter<T> { public final class Adapter<T> extends TypeAdapter<T> {
private final ObjectConstructor<T> constructor; private final ObjectConstructor<T> constructor;
private final Map<String, BoundField> boundFields; private final Map<String, BoundField> boundFields;
private Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) { private Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
this.constructor = constructor; this.constructor = constructor;
this.boundFields = boundFields; this.boundFields = boundFields;
} }
@Override @Override
public T read(JsonReader in) throws IOException { public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
T instance = constructor.construct(); T instance = constructor.construct();
// TODO: null out the other fields? // TODO: null out the other fields?
try { try {
in.beginObject(); in.beginObject();
while (in.hasNext()) { while (in.hasNext()) {
String name = in.nextName(); String name = in.nextName();
BoundField field = boundFields.get(name); BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) { if (field == null || !field.deserialized) {
// TODO: define a better policy // TODO: define a better policy
in.skipValue(); in.skipValue();
} else { } else {
field.read(in, instance); field.read(in, instance);
} }
} }
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
in.endObject(); in.endObject();
return instance; return instance;
} }
@Override @Override
public void write(JsonWriter out, T value) throws IOException { public void write(JsonWriter out, T value) throws IOException {
if (value == null) { if (value == null) {
out.nullValue(); // TODO: better policy here? out.nullValue(); // TODO: better policy here?
return; return;
} }
out.beginObject(); out.beginObject();
try { try {
for (BoundField boundField : boundFields.values()) { for (BoundField boundField : boundFields.values()) {
if (boundField.serialized) { if (boundField.serialized) {
out.name(boundField.name); out.name(boundField.name);
boundField.write(out, value); boundField.write(out, value);
} }
} }
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new AssertionError(); throw new AssertionError();
} }
out.endObject(); out.endObject();
} }
} }
} }
@@ -1,67 +1,67 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
/** /**
* Adapter for java.sql.Date. Although this class appears stateless, it is not. * Adapter for java.sql.Date. Although this class appears stateless, it is not.
* DateFormat captures its time zone and locale when it is created, which gives * DateFormat captures its time zone and locale when it is created, which gives
* this class state. DateFormat isn't thread safe either, so this class has * this class state. DateFormat isn't thread safe either, so this class has
* to synchronize its read and write methods. * to synchronize its read and write methods.
*/ */
public final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> { public final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
return typeToken.getRawType() == java.sql.Date.class return typeToken.getRawType() == java.sql.Date.class
? (TypeAdapter<T>) new SqlDateTypeAdapter() : null; ? (TypeAdapter<T>) new SqlDateTypeAdapter() : null;
} }
}; };
private final DateFormat format = new SimpleDateFormat("MMM d, yyyy"); private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");
@Override @Override
public synchronized java.sql.Date read(JsonReader in) throws IOException { public synchronized java.sql.Date read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
try { try {
final long utilDate = format.parse(in.nextString()).getTime(); final long utilDate = format.parse(in.nextString()).getTime();
return new java.sql.Date(utilDate); return new java.sql.Date(utilDate);
} catch (ParseException e) { } catch (ParseException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} }
} }
@Override @Override
public synchronized void write(JsonWriter out, java.sql.Date value) throws IOException { public synchronized void write(JsonWriter out, java.sql.Date value) throws IOException {
out.value(value == null ? null : format.format(value)); out.value(value == null ? null : format.format(value));
} }
} }
@@ -1,66 +1,66 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import java.io.IOException; import java.io.IOException;
import java.sql.Time; import java.sql.Time;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
/** /**
* Adapter for Time. Although this class appears stateless, it is not. * Adapter for Time. Although this class appears stateless, it is not.
* DateFormat captures its time zone and locale when it is created, which gives * DateFormat captures its time zone and locale when it is created, which gives
* this class state. DateFormat isn't thread safe either, so this class has * this class state. DateFormat isn't thread safe either, so this class has
* to synchronize its read and write methods. * to synchronize its read and write methods.
*/ */
public final class TimeTypeAdapter extends TypeAdapter<Time> { public final class TimeTypeAdapter extends TypeAdapter<Time> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new TimeTypeAdapter() : null; return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new TimeTypeAdapter() : null;
} }
}; };
private final DateFormat format = new SimpleDateFormat("hh:mm:ss a"); private final DateFormat format = new SimpleDateFormat("hh:mm:ss a");
@Override public synchronized Time read(JsonReader in) throws IOException { @Override public synchronized Time read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) { if (in.peek() == JsonToken.NULL) {
in.nextNull(); in.nextNull();
return null; return null;
} }
try { try {
Date date = format.parse(in.nextString()); Date date = format.parse(in.nextString());
return new Time(date.getTime()); return new Time(date.getTime());
} catch (ParseException e) { } catch (ParseException e) {
throw new JsonSyntaxException(e); throw new JsonSyntaxException(e);
} }
} }
@Override public synchronized void write(JsonWriter out, Time value) throws IOException { @Override public synchronized void write(JsonWriter out, Time value) throws IOException {
out.value(value == null ? null : format.format(value)); out.value(value == null ? null : format.format(value));
} }
} }
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,7 @@
/** /**
* Do NOT use any class in this package as they are meant for internal use in Gson. * Do NOT use any class in this package as they are meant for internal use in Gson.
* These classes will very likely change incompatibly in future versions. You have been warned. * These classes will very likely change incompatibly in future versions. You have been warned.
* *
* @author Inderjeet Singh, Joel Leitch, Jesse Wilson * @author Inderjeet Singh, Joel Leitch, Jesse Wilson
*/ */
package com.google.gson.internal; package com.google.gson.internal;
+11 -11
View File
@@ -1,11 +1,11 @@
/** /**
* This package provides the {@link com.google.gson.Gson} class to convert Json to Java and * This package provides the {@link com.google.gson.Gson} class to convert Json to Java and
* vice-versa. * vice-versa.
* *
* <p>The primary class to use is {@link com.google.gson.Gson} which can be constructed with * <p>The primary class to use is {@link com.google.gson.Gson} which can be constructed with
* {@code new Gson()} (using default settings) or by using {@link com.google.gson.GsonBuilder} * {@code new Gson()} (using default settings) or by using {@link com.google.gson.GsonBuilder}
* (to configure various options such as using versioning and so on).</p> * (to configure various options such as using versioning and so on).</p>
* *
* @author Inderjeet Singh, Joel Leitch * @author Inderjeet Singh, Joel Leitch
*/ */
package com.google.gson; package com.google.gson;
+305 -305
View File
@@ -1,305 +1,305 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2008 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.reflect; package com.google.gson.reflect;
import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Types;
import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.$Gson$Preconditions;
import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable; import java.lang.reflect.TypeVariable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Represents a generic type {@code T}. Java doesn't yet provide a way to * Represents a generic type {@code T}. Java doesn't yet provide a way to
* represent generic types, so this class does. Forces clients to create a * represent generic types, so this class does. Forces clients to create a
* subclass of this class which enables retrieval the type information even at * subclass of this class which enables retrieval the type information even at
* runtime. * runtime.
* *
* <p>For example, to create a type literal for {@code List<String>}, you can * <p>For example, to create a type literal for {@code List<String>}, you can
* create an empty anonymous inner class: * create an empty anonymous inner class:
* *
* <p> * <p>
* {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};} * {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}
* *
* <p>This syntax cannot be used to create type literals that have wildcard * <p>This syntax cannot be used to create type literals that have wildcard
* parameters, such as {@code Class<?>} or {@code List<? extends CharSequence>}. * parameters, such as {@code Class<?>} or {@code List<? extends CharSequence>}.
* *
* @author Bob Lee * @author Bob Lee
* @author Sven Mawson * @author Sven Mawson
* @author Jesse Wilson * @author Jesse Wilson
*/ */
public class TypeToken<T> { public class TypeToken<T> {
final Class<? super T> rawType; final Class<? super T> rawType;
final Type type; final Type type;
final int hashCode; final int hashCode;
/** /**
* Constructs a new type literal. Derives represented class from type * Constructs a new type literal. Derives represented class from type
* parameter. * parameter.
* *
* <p>Clients create an empty anonymous subclass. Doing so embeds the type * <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it * parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure. * at runtime despite erasure.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected TypeToken() { protected TypeToken() {
this.type = getSuperclassTypeParameter(getClass()); this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<? super T>) $Gson$Types.getRawType(type); this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
this.hashCode = type.hashCode(); this.hashCode = type.hashCode();
} }
/** /**
* Unsafe. Constructs a type literal manually. * Unsafe. Constructs a type literal manually.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
TypeToken(Type type) { TypeToken(Type type) {
this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type)); this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type); this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
this.hashCode = this.type.hashCode(); this.hashCode = this.type.hashCode();
} }
/** /**
* Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
* canonical form}. * canonical form}.
*/ */
static Type getSuperclassTypeParameter(Class<?> subclass) { static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass(); Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) { if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter."); throw new RuntimeException("Missing type parameter.");
} }
ParameterizedType parameterized = (ParameterizedType) superclass; ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
} }
/** /**
* Returns the raw (non-generic) type for this type. * Returns the raw (non-generic) type for this type.
*/ */
public final Class<? super T> getRawType() { public final Class<? super T> getRawType() {
return rawType; return rawType;
} }
/** /**
* Gets underlying {@code Type} instance. * Gets underlying {@code Type} instance.
*/ */
public final Type getType() { public final Type getType() {
return type; return type;
} }
/** /**
* Check if this type is assignable from the given class object. * Check if this type is assignable from the given class object.
* *
* @deprecated this implementation may be inconsistent with javac for types * @deprecated this implementation may be inconsistent with javac for types
* with wildcards. * with wildcards.
*/ */
@Deprecated @Deprecated
public boolean isAssignableFrom(Class<?> cls) { public boolean isAssignableFrom(Class<?> cls) {
return isAssignableFrom((Type) cls); return isAssignableFrom((Type) cls);
} }
/** /**
* Check if this type is assignable from the given Type. * Check if this type is assignable from the given Type.
* *
* @deprecated this implementation may be inconsistent with javac for types * @deprecated this implementation may be inconsistent with javac for types
* with wildcards. * with wildcards.
*/ */
@Deprecated @Deprecated
public boolean isAssignableFrom(Type from) { public boolean isAssignableFrom(Type from) {
if (from == null) { if (from == null) {
return false; return false;
} }
if (type.equals(from)) { if (type.equals(from)) {
return true; return true;
} }
if (type instanceof Class<?>) { if (type instanceof Class<?>) {
return rawType.isAssignableFrom($Gson$Types.getRawType(from)); return rawType.isAssignableFrom($Gson$Types.getRawType(from));
} else if (type instanceof ParameterizedType) { } else if (type instanceof ParameterizedType) {
return isAssignableFrom(from, (ParameterizedType) type, return isAssignableFrom(from, (ParameterizedType) type,
new HashMap<String, Type>()); new HashMap<String, Type>());
} else if (type instanceof GenericArrayType) { } else if (type instanceof GenericArrayType) {
return rawType.isAssignableFrom($Gson$Types.getRawType(from)) return rawType.isAssignableFrom($Gson$Types.getRawType(from))
&& isAssignableFrom(from, (GenericArrayType) type); && isAssignableFrom(from, (GenericArrayType) type);
} else { } else {
throw buildUnexpectedTypeError( throw buildUnexpectedTypeError(
type, Class.class, ParameterizedType.class, GenericArrayType.class); type, Class.class, ParameterizedType.class, GenericArrayType.class);
} }
} }
/** /**
* Check if this type is assignable from the given type token. * Check if this type is assignable from the given type token.
* *
* @deprecated this implementation may be inconsistent with javac for types * @deprecated this implementation may be inconsistent with javac for types
* with wildcards. * with wildcards.
*/ */
@Deprecated @Deprecated
public boolean isAssignableFrom(TypeToken<?> token) { public boolean isAssignableFrom(TypeToken<?> token) {
return isAssignableFrom(token.getType()); return isAssignableFrom(token.getType());
} }
/** /**
* Private helper function that performs some assignability checks for * Private helper function that performs some assignability checks for
* the provided GenericArrayType. * the provided GenericArrayType.
*/ */
private static boolean isAssignableFrom(Type from, GenericArrayType to) { private static boolean isAssignableFrom(Type from, GenericArrayType to) {
Type toGenericComponentType = to.getGenericComponentType(); Type toGenericComponentType = to.getGenericComponentType();
if (toGenericComponentType instanceof ParameterizedType) { if (toGenericComponentType instanceof ParameterizedType) {
Type t = from; Type t = from;
if (from instanceof GenericArrayType) { if (from instanceof GenericArrayType) {
t = ((GenericArrayType) from).getGenericComponentType(); t = ((GenericArrayType) from).getGenericComponentType();
} else if (from instanceof Class<?>) { } else if (from instanceof Class<?>) {
Class<?> classType = (Class<?>) from; Class<?> classType = (Class<?>) from;
while (classType.isArray()) { while (classType.isArray()) {
classType = classType.getComponentType(); classType = classType.getComponentType();
} }
t = classType; t = classType;
} }
return isAssignableFrom(t, (ParameterizedType) toGenericComponentType, return isAssignableFrom(t, (ParameterizedType) toGenericComponentType,
new HashMap<String, Type>()); new HashMap<String, Type>());
} }
// No generic defined on "to"; therefore, return true and let other // No generic defined on "to"; therefore, return true and let other
// checks determine assignability // checks determine assignability
return true; return true;
} }
/** /**
* Private recursive helper function to actually do the type-safe checking * Private recursive helper function to actually do the type-safe checking
* of assignability. * of assignability.
*/ */
private static boolean isAssignableFrom(Type from, ParameterizedType to, private static boolean isAssignableFrom(Type from, ParameterizedType to,
Map<String, Type> typeVarMap) { Map<String, Type> typeVarMap) {
if (from == null) { if (from == null) {
return false; return false;
} }
if (to.equals(from)) { if (to.equals(from)) {
return true; return true;
} }
// First figure out the class and any type information. // First figure out the class and any type information.
Class<?> clazz = $Gson$Types.getRawType(from); Class<?> clazz = $Gson$Types.getRawType(from);
ParameterizedType ptype = null; ParameterizedType ptype = null;
if (from instanceof ParameterizedType) { if (from instanceof ParameterizedType) {
ptype = (ParameterizedType) from; ptype = (ParameterizedType) from;
} }
// Load up parameterized variable info if it was parameterized. // Load up parameterized variable info if it was parameterized.
if (ptype != null) { if (ptype != null) {
Type[] tArgs = ptype.getActualTypeArguments(); Type[] tArgs = ptype.getActualTypeArguments();
TypeVariable<?>[] tParams = clazz.getTypeParameters(); TypeVariable<?>[] tParams = clazz.getTypeParameters();
for (int i = 0; i < tArgs.length; i++) { for (int i = 0; i < tArgs.length; i++) {
Type arg = tArgs[i]; Type arg = tArgs[i];
TypeVariable<?> var = tParams[i]; TypeVariable<?> var = tParams[i];
while (arg instanceof TypeVariable<?>) { while (arg instanceof TypeVariable<?>) {
TypeVariable<?> v = (TypeVariable<?>) arg; TypeVariable<?> v = (TypeVariable<?>) arg;
arg = typeVarMap.get(v.getName()); arg = typeVarMap.get(v.getName());
} }
typeVarMap.put(var.getName(), arg); typeVarMap.put(var.getName(), arg);
} }
// check if they are equivalent under our current mapping. // check if they are equivalent under our current mapping.
if (typeEquals(ptype, to, typeVarMap)) { if (typeEquals(ptype, to, typeVarMap)) {
return true; return true;
} }
} }
for (Type itype : clazz.getGenericInterfaces()) { for (Type itype : clazz.getGenericInterfaces()) {
if (isAssignableFrom(itype, to, new HashMap<String, Type>(typeVarMap))) { if (isAssignableFrom(itype, to, new HashMap<String, Type>(typeVarMap))) {
return true; return true;
} }
} }
// Interfaces didn't work, try the superclass. // Interfaces didn't work, try the superclass.
Type sType = clazz.getGenericSuperclass(); Type sType = clazz.getGenericSuperclass();
return isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap)); return isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap));
} }
/** /**
* Checks if two parameterized types are exactly equal, under the variable * Checks if two parameterized types are exactly equal, under the variable
* replacement described in the typeVarMap. * replacement described in the typeVarMap.
*/ */
private static boolean typeEquals(ParameterizedType from, private static boolean typeEquals(ParameterizedType from,
ParameterizedType to, Map<String, Type> typeVarMap) { ParameterizedType to, Map<String, Type> typeVarMap) {
if (from.getRawType().equals(to.getRawType())) { if (from.getRawType().equals(to.getRawType())) {
Type[] fromArgs = from.getActualTypeArguments(); Type[] fromArgs = from.getActualTypeArguments();
Type[] toArgs = to.getActualTypeArguments(); Type[] toArgs = to.getActualTypeArguments();
for (int i = 0; i < fromArgs.length; i++) { for (int i = 0; i < fromArgs.length; i++) {
if (!matches(fromArgs[i], toArgs[i], typeVarMap)) { if (!matches(fromArgs[i], toArgs[i], typeVarMap)) {
return false; return false;
} }
} }
return true; return true;
} }
return false; return false;
} }
private static AssertionError buildUnexpectedTypeError( private static AssertionError buildUnexpectedTypeError(
Type token, Class<?>... expected) { Type token, Class<?>... expected) {
// Build exception message // Build exception message
StringBuilder exceptionMessage = StringBuilder exceptionMessage =
new StringBuilder("Unexpected type. Expected one of: "); new StringBuilder("Unexpected type. Expected one of: ");
for (Class<?> clazz : expected) { for (Class<?> clazz : expected) {
exceptionMessage.append(clazz.getName()).append(", "); exceptionMessage.append(clazz.getName()).append(", ");
} }
exceptionMessage.append("but got: ").append(token.getClass().getName()) exceptionMessage.append("but got: ").append(token.getClass().getName())
.append(", for type token: ").append(token.toString()).append('.'); .append(", for type token: ").append(token.toString()).append('.');
return new AssertionError(exceptionMessage.toString()); return new AssertionError(exceptionMessage.toString());
} }
/** /**
* Checks if two types are the same or are equivalent under a variable mapping * Checks if two types are the same or are equivalent under a variable mapping
* given in the type map that was provided. * given in the type map that was provided.
*/ */
private static boolean matches(Type from, Type to, Map<String, Type> typeMap) { private static boolean matches(Type from, Type to, Map<String, Type> typeMap) {
return to.equals(from) return to.equals(from)
|| (from instanceof TypeVariable || (from instanceof TypeVariable
&& to.equals(typeMap.get(((TypeVariable<?>) from).getName()))); && to.equals(typeMap.get(((TypeVariable<?>) from).getName())));
} }
@Override public final int hashCode() { @Override public final int hashCode() {
return this.hashCode; return this.hashCode;
} }
@Override public final boolean equals(Object o) { @Override public final boolean equals(Object o) {
return o instanceof TypeToken<?> return o instanceof TypeToken<?>
&& $Gson$Types.equals(type, ((TypeToken<?>) o).type); && $Gson$Types.equals(type, ((TypeToken<?>) o).type);
} }
@Override public final String toString() { @Override public final String toString() {
return $Gson$Types.typeToString(type); return $Gson$Types.typeToString(type);
} }
/** /**
* Gets type literal for the given {@code Type} instance. * Gets type literal for the given {@code Type} instance.
*/ */
public static TypeToken<?> get(Type type) { public static TypeToken<?> get(Type type) {
return new TypeToken<Object>(type); return new TypeToken<Object>(type);
} }
/** /**
* Gets type literal for the given {@code Class} instance. * Gets type literal for the given {@code Class} instance.
*/ */
public static <T> TypeToken<T> get(Class<T> type) { public static <T> TypeToken<T> get(Class<T> type) {
return new TypeToken<T>(type); return new TypeToken<T>(type);
} }
} }
@@ -1,6 +1,6 @@
/** /**
* This package provides utility classes for finding type information for generic types. * This package provides utility classes for finding type information for generic types.
* *
* @author Inderjeet Singh, Joel Leitch * @author Inderjeet Singh, Joel Leitch
*/ */
package com.google.gson.reflect; package com.google.gson.reflect;
File diff suppressed because it is too large Load Diff
+71 -71
View File
@@ -1,71 +1,71 @@
/* /*
* Copyright (C) 2010 Google Inc. * Copyright (C) 2010 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.stream; package com.google.gson.stream;
/** /**
* Lexical scoping elements within a JSON reader or writer. * Lexical scoping elements within a JSON reader or writer.
* *
* @author Jesse Wilson * @author Jesse Wilson
* @since 1.6 * @since 1.6
*/ */
enum JsonScope { enum JsonScope {
/** /**
* An array with no elements requires no separators or newlines before * An array with no elements requires no separators or newlines before
* it is closed. * it is closed.
*/ */
EMPTY_ARRAY, EMPTY_ARRAY,
/** /**
* A array with at least one value requires a comma and newline before * A array with at least one value requires a comma and newline before
* the next element. * the next element.
*/ */
NONEMPTY_ARRAY, NONEMPTY_ARRAY,
/** /**
* An object with no name/value pairs requires no separators or newlines * An object with no name/value pairs requires no separators or newlines
* before it is closed. * before it is closed.
*/ */
EMPTY_OBJECT, EMPTY_OBJECT,
/** /**
* An object whose most recent element is a key. The next element must * An object whose most recent element is a key. The next element must
* be a value. * be a value.
*/ */
DANGLING_NAME, DANGLING_NAME,
/** /**
* An object with at least one name/value pair requires a comma and * An object with at least one name/value pair requires a comma and
* newline before the next element. * newline before the next element.
*/ */
NONEMPTY_OBJECT, NONEMPTY_OBJECT,
/** /**
* No object or array has been started. * No object or array has been started.
*/ */
EMPTY_DOCUMENT, EMPTY_DOCUMENT,
/** /**
* A document with at an array or object. * A document with at an array or object.
*/ */
NONEMPTY_DOCUMENT, NONEMPTY_DOCUMENT,
/** /**
* A document that's been closed and cannot be accessed. * A document that's been closed and cannot be accessed.
*/ */
CLOSED, CLOSED,
} }
+85 -85
View File
@@ -1,85 +1,85 @@
/* /*
* Copyright (C) 2010 Google Inc. * Copyright (C) 2010 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.stream; package com.google.gson.stream;
/** /**
* A structure, name or value type in a JSON-encoded string. * A structure, name or value type in a JSON-encoded string.
* *
* @author Jesse Wilson * @author Jesse Wilson
* @since 1.6 * @since 1.6
*/ */
public enum JsonToken { public enum JsonToken {
/** /**
* The opening of a JSON array. Written using {@link JsonWriter#beginObject} * The opening of a JSON array. Written using {@link JsonWriter#beginObject}
* and read using {@link JsonReader#beginObject}. * and read using {@link JsonReader#beginObject}.
*/ */
BEGIN_ARRAY, BEGIN_ARRAY,
/** /**
* The closing of a JSON array. Written using {@link JsonWriter#endArray} * The closing of a JSON array. Written using {@link JsonWriter#endArray}
* and read using {@link JsonReader#endArray}. * and read using {@link JsonReader#endArray}.
*/ */
END_ARRAY, END_ARRAY,
/** /**
* The opening of a JSON object. Written using {@link JsonWriter#beginObject} * The opening of a JSON object. Written using {@link JsonWriter#beginObject}
* and read using {@link JsonReader#beginObject}. * and read using {@link JsonReader#beginObject}.
*/ */
BEGIN_OBJECT, BEGIN_OBJECT,
/** /**
* The closing of a JSON object. Written using {@link JsonWriter#endObject} * The closing of a JSON object. Written using {@link JsonWriter#endObject}
* and read using {@link JsonReader#endObject}. * and read using {@link JsonReader#endObject}.
*/ */
END_OBJECT, END_OBJECT,
/** /**
* A JSON property name. Within objects, tokens alternate between names and * A JSON property name. Within objects, tokens alternate between names and
* their values. Written using {@link JsonWriter#name} and read using {@link * their values. Written using {@link JsonWriter#name} and read using {@link
* JsonReader#nextName} * JsonReader#nextName}
*/ */
NAME, NAME,
/** /**
* A JSON string. * A JSON string.
*/ */
STRING, STRING,
/** /**
* A JSON number represented in this API by a Java {@code double}, {@code * A JSON number represented in this API by a Java {@code double}, {@code
* long}, or {@code int}. * long}, or {@code int}.
*/ */
NUMBER, NUMBER,
/** /**
* A JSON {@code true} or {@code false}. * A JSON {@code true} or {@code false}.
*/ */
BOOLEAN, BOOLEAN,
/** /**
* A JSON {@code null}. * A JSON {@code null}.
*/ */
NULL, NULL,
/** /**
* The end of the JSON stream. This sentinel value is returned by {@link * The end of the JSON stream. This sentinel value is returned by {@link
* JsonReader#peek()} to signal that the JSON-encoded value has no more * JsonReader#peek()} to signal that the JSON-encoded value has no more
* tokens. * tokens.
*/ */
END_DOCUMENT END_DOCUMENT
} }
File diff suppressed because it is too large Load Diff
@@ -1,44 +1,44 @@
/* /*
* Copyright (C) 2010 Google Inc. * Copyright (C) 2010 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.stream; package com.google.gson.stream;
import java.io.IOException; import java.io.IOException;
/** /**
* Thrown when a reader encounters malformed JSON. Some syntax errors can be * Thrown when a reader encounters malformed JSON. Some syntax errors can be
* ignored by calling {@link JsonReader#setLenient(boolean)}. * ignored by calling {@link JsonReader#setLenient(boolean)}.
*/ */
public final class MalformedJsonException extends IOException { public final class MalformedJsonException extends IOException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public MalformedJsonException(String msg) { public MalformedJsonException(String msg) {
super(msg); super(msg);
} }
public MalformedJsonException(String msg, Throwable throwable) { public MalformedJsonException(String msg, Throwable throwable) {
super(msg); super(msg);
// Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException
// with a constructor with Throwable. This was done in Java 1.6 // with a constructor with Throwable. This was done in Java 1.6
initCause(throwable); initCause(throwable);
} }
public MalformedJsonException(Throwable throwable) { public MalformedJsonException(Throwable throwable) {
// Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException // Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException
// with a constructor with Throwable. This was done in Java 1.6 // with a constructor with Throwable. This was done in Java 1.6
initCause(throwable); initCause(throwable);
} }
} }
+60 -60
View File
@@ -1,60 +1,60 @@
/* /*
* Copyright (C) 2011 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson.stream; package com.google.gson.stream;
/** /**
* A pool of string instances. Unlike the {@link String#intern() VM's * A pool of string instances. Unlike the {@link String#intern() VM's
* interned strings}, this pool provides no guarantee of reference equality. * interned strings}, this pool provides no guarantee of reference equality.
* It is intended only to save allocations. This class is not thread safe. * It is intended only to save allocations. This class is not thread safe.
*/ */
final class StringPool { final class StringPool {
private final String[] pool = new String[512]; private final String[] pool = new String[512];
/** /**
* Returns a string equal to {@code new String(array, start, length)}. * Returns a string equal to {@code new String(array, start, length)}.
*/ */
public String get(char[] array, int start, int length) { public String get(char[] array, int start, int length) {
// Compute an arbitrary hash of the content // Compute an arbitrary hash of the content
int hashCode = 0; int hashCode = 0;
for (int i = start; i < start + length; i++) { for (int i = start; i < start + length; i++) {
hashCode = (hashCode * 31) + array[i]; hashCode = (hashCode * 31) + array[i];
} }
// Pick a bucket using Doug Lea's supplemental secondaryHash function (from HashMap) // Pick a bucket using Doug Lea's supplemental secondaryHash function (from HashMap)
hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12); hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);
hashCode ^= (hashCode >>> 7) ^ (hashCode >>> 4); hashCode ^= (hashCode >>> 7) ^ (hashCode >>> 4);
int index = hashCode & (pool.length - 1); int index = hashCode & (pool.length - 1);
String pooled = pool[index]; String pooled = pool[index];
if (pooled == null || pooled.length() != length) { if (pooled == null || pooled.length() != length) {
String result = new String(array, start, length); String result = new String(array, start, length);
pool[index] = result; pool[index] = result;
return result; return result;
} }
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
if (pooled.charAt(i) != array[start + i]) { if (pooled.charAt(i) != array[start + i]) {
String result = new String(array, start, length); String result = new String(array, start, length);
pool[index] = result; pool[index] = result;
return result; return result;
} }
} }
return pooled; return pooled;
} }
} }
@@ -47,7 +47,7 @@ public class IOThreadManager {
} }
Thread lt = ThreadTool.makeVThreadIfSupport("数据包计时重发线程", () -> { Thread lt = ThreadTool.makeVThreadIfSupport("数据包计时重发线程", () -> {
try { try {
while (AB.get()) { while (AB.get()) {
@@ -57,7 +57,7 @@ public class IOThreadManager {
} }
}); });
Thread ls = ThreadTool.makeVThreadIfSupport("本地发送线程", () -> { Thread ls = ThreadTool.makeVThreadIfSupport("本地发送线程", () -> {
try { try {
while (AB.get()) { while (AB.get()) {
@@ -77,7 +77,6 @@ public class IOThreadManager {
sbk.number = 0; sbk.number = 0;
sbk.command = 3; sbk.command = 3;
klc.submitDataBlockNoDelay(sbk); klc.submitDataBlockNoDelay(sbk);
e.printStackTrace();
}finally { }finally {
try { try {
tc.getDout().close(); tc.getDout().close();
@@ -86,7 +85,7 @@ public class IOThreadManager {
} }
} }
}); });
Thread lr = ThreadTool.makeVThreadIfSupport("本地接收线程", () -> { Thread lr = ThreadTool.makeVThreadIfSupport("本地接收线程", () -> {
try { try {
while (AB.get()) { while (AB.get()) {
KLALBBlock ks = tc.packBlock(); KLALBBlock ks = tc.packBlock();
@@ -105,7 +104,6 @@ public class IOThreadManager {
sbk.number = 0; sbk.number = 0;
sbk.command = 3; sbk.command = 3;
klc.submitDataBlockNoDelay(sbk); klc.submitDataBlockNoDelay(sbk);
e.printStackTrace();
} finally { } finally {
try { try {
tc.getDin().close(); tc.getDin().close();
@@ -143,7 +141,7 @@ public class IOThreadManager {
} }
klc.getRemotetcps().add(tc); klc.getRemotetcps().add(tc);
try { try {
Thread rs = ThreadTool.makeVThreadIfSupport("远程发送线程", () -> { Thread rs = ThreadTool.makeVThreadIfSupport("远程发送线程", () -> {
try { try {
while (true) { while (true) {
@@ -151,17 +149,15 @@ public class IOThreadManager {
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace();
} }
}); });
Thread rr = ThreadTool.makeVThreadIfSupport("远程接收线程", () -> { Thread rr = ThreadTool.makeVThreadIfSupport("远程接收线程", () -> {
try { try {
while (true) { while (true) {
klc.remoteReceive(tc); klc.remoteReceive(tc);
} }
} catch (Exception e) { } catch (Exception e) {
rs.interrupt(); rs.interrupt();
e.printStackTrace();
} }
}); });
rs.start(); rs.start();
@@ -10,12 +10,12 @@ import org.kne.cloud.network.mport.IPPort;
public class KLALBBlock implements Comparable<KLALBBlock>{ public class KLALBBlock implements Comparable<KLALBBlock>{
private static AtomicLong sng=new AtomicLong(1); private static AtomicLong sng=new AtomicLong(1);
public long sn;//每个数据包的唯一编号 public long sn;//每个数据包的唯一编号
public int cuid;//用于识别数据包的stream ID号 public int cuid;//用于识别数据包的stream ID号
public long number;//数据包的编号用于排序 public long number;//数据包的编号用于排序
public byte[]data;//数据内容 public byte[]data;//数据内容
public int command;//功能标记 0=PING 1=PONG 2=SYN 3=RST public int command;//功能标记 0=PING 1=PONG 2=SYN 3=RST
public long pingtime;//PING计时器 public long pingtime;//PING计时器
public int cacheused; public int cacheused;
public String lservice; public String lservice;
+13 -11
View File
@@ -15,8 +15,8 @@ public class KLALBCM {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
if(args.length==0){ if(args.length==0){
System.out.println("命令行参数输入服务器任意一条线路的地址:端口可以下载服务器线路列表"); System.out.println("命令行参数输入服务器任意一条线路的地址:端口可以下载服务器线路列表");
System.out.println("命令行参数输入服务器名称即可启动负载均衡"); System.out.println("命令行参数输入服务器名称即可启动负载均衡");
}else if(args.length==1) { }else if(args.length==1) {
if(args[0].equals("-gui")) { if(args[0].equals("-gui")) {
KLALBClientGUI.main(args); KLALBClientGUI.main(args);
@@ -27,33 +27,35 @@ public class KLALBCM {
File pdis=KLALBIPList.getSLdir(args[0]); File pdis=KLALBIPList.getSLdir(args[0]);
File f=new File(pdis,"iplist.json"); File f=new File(pdis,"iplist.json");
if(f.exists()) { if(f.exists()) {
System.out.println("加载线路列表:"+f); System.out.println("加载线路列表:"+f);
byte[] bytes;
try { try {
KLALBIPList.updateIPList(args[0]); KLALBIPList.updateIPList(args[0]);
bytes = Files.readAllBytes(Paths.get(f.toURI())); STJson stj=new STJson(new String(Files.readAllBytes(Paths.get(f.toURI()))));
STJson stj=new STJson(new String(bytes));
KLALBClient kc= new KLALBClient(); KLALBClient kc= new KLALBClient();
kc.getTls().addAll(stj.getTunnels()); kc.getTls().addAll(stj.getTunnels());
kc.connectTunnel(); kc.connectTunnel();
List<ServiceElement> lse=stj.getServices();
ProxyJson pj=new ProxyJson(new File(pdis,"services.json"), stj);
kc.getPet().addAll(pj.getPls());
kc.listenProxy();
/* List<ServiceElement> lse=stj.getServices();
for (Iterator<ServiceElement> iterator = lse.iterator(); iterator.hasNext();) { for (Iterator<ServiceElement> iterator = lse.iterator(); iterator.hasNext();) {
ServiceElement serviceElement = (ServiceElement) iterator.next(); ServiceElement serviceElement = (ServiceElement) iterator.next();
ProxyIPPortProperties pippp=new ProxyIPPortProperties(pdis, serviceElement.name, "127.0.0.1", serviceElement.ipport.getPort()); ProxyIPPortProperties pippp=new ProxyIPPortProperties(pdis, serviceElement.name, "0.0.0.0", serviceElement.ipport.getPort());
try { try {
kc.open(pippp.getBindPort(),serviceElement, pippp.getBindIP()); kc.open(pippp.getBindPort(),serviceElement, pippp.getBindIP());
}catch(BindException e) { }catch(BindException e) {
System.out.println("打开端口失败:"+pippp.getBindIP()+" "+pippp.getBindPort()); System.out.println("打开端口失败:"+pippp.getBindIP()+" "+pippp.getBindPort());
e.printStackTrace(); e.printStackTrace();
} }
} }*/
}catch (IOException e) { }catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
}else { }else {
System.out.println("线路列表不存在"); System.out.println("线路列表不存在");
} }
} }
}else { }else {
@@ -25,6 +25,8 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.text.html.HTMLDocument.HTMLReader.PreAction;
import org.kne.cloud.network.mport.IPPort; import org.kne.cloud.network.mport.IPPort;
import org.kne.cloud.network.mport.ServiceElement; import org.kne.cloud.network.mport.ServiceElement;
import org.kne.cloud.network.mport.ThreadTool; import org.kne.cloud.network.mport.ThreadTool;
@@ -37,19 +39,19 @@ public class KLALBClient {
private IOThreadManager iom=new IOThreadManager(); private IOThreadManager iom=new IOThreadManager();
private List<Tunnel> tls=new ArrayList<>(); private List<Tunnel> tls=new ArrayList<>();
private List<TCPListener> tcpl=new ArrayList<>(); private List<TCPListener> tcpl=new ArrayList<>();
private List<ProxyElement> pet=new ArrayList<>();
public void open(int port, ServiceElement sel,String bindip) throws IOException { private void open(ProxyElement pe) throws IOException {
TCPListener tl=new TCPListener(port,bindip); TCPListener tl=new TCPListener(pe.getIpport().getPort(),pe.getIpport().getIp());
tl.setCon((s)->{ tl.setCon((s)->{
LocalTCPConnection tcc = null; LocalTCPConnection tcc = null;
try { try {
tcc = new LocalTCPConnection(s); tcc = new LocalTCPConnection(s);
tcc.setServiceElement(sel); tcc.setServiceElement(pe.getSe());
//System.out.println("TCP"+tcc.getCuid()+"已连接"); //System.out.println("TCP"+tcc.getCuid()+"已连接");
iom.handleLocal(tcc,true); iom.handleLocal(tcc,true);
//System.out.println("TCP"+tcc.getCuid()+"已关闭"); //System.out.println("TCP"+tcc.getCuid()+"已关闭");
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
}finally { }finally {
@@ -60,12 +62,22 @@ public class KLALBClient {
}); });
tl.open(); tl.open();
tcpl.add(tl); tcpl.add(tl);
System.out.println(sel.name+"映射已启动 端口:"+port+" 绑定地址:"+bindip); System.out.println(pe.getSe().name+"映射已启动 端口:"+pe.getIpport().getPort()+" 绑定地址:"+pe.getIpport().getIp());
}
public void listenProxy() {
for (int i = 0; i < pet.size(); i++) {
ProxyElement pe=pet.get(i);
try {
open(pe);
} catch (IOException e) {
e.printStackTrace();
}
}
} }
public void connectTunnel() { public void connectTunnel() {
for (int i = 0; i < tls.size(); i++) { for (int i = 0; i < tls.size(); i++) {
Tunnel tll=tls.get(i); Tunnel tll=tls.get(i);
ThreadTool.makeVThreadIfSupport("隧道监视线程", ()->{ ThreadTool.makeVThreadIfSupport("隧道监视线程", ()->{
int re=0; int re=0;
RemoteTCPConnection tc=null; RemoteTCPConnection tc=null;
while(iom.isOpen()) { while(iom.isOpen()) {
@@ -84,10 +96,10 @@ public class KLALBClient {
throw new EOFException(); throw new EOFException();
} }
re=0; re=0;
System.out.println(tll+":连接成功"); System.out.println(tll+":连接成功");
tll.setState(true); tll.setState(true);
iom.handleRemote(tc); iom.handleRemote(tc);
System.out.println(tll+":连接断开"); System.out.println(tll+":连接断开");
tll.setState(false); tll.setState(false);
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
e.printStackTrace(); e.printStackTrace();
@@ -112,6 +124,9 @@ public class KLALBClient {
public List<Tunnel> getTls() { public List<Tunnel> getTls() {
return tls; return tls;
} }
public List<ProxyElement> getPet() {
return pet;
}
public List<ServiceElement> services=new ArrayList<ServiceElement>(); public List<ServiceElement> services=new ArrayList<ServiceElement>();
public List<ServiceElement> getServices() { public List<ServiceElement> getServices() {
@@ -123,6 +138,9 @@ public class KLALBClient {
TCPListener tl = (TCPListener) iterator.next(); TCPListener tl = (TCPListener) iterator.next();
tl.close(); tl.close();
} }
tls.forEach((v)->{
v.destroyFrpc();
});
} }
@@ -85,13 +85,13 @@ public class KLALBClientGUI extends XFrame {
@Override @Override
public void componentShown(ComponentEvent e) { public void componentShown(ComponentEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void componentResized(ComponentEvent e) { public void componentResized(ComponentEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -102,7 +102,7 @@ public class KLALBClientGUI extends XFrame {
@Override @Override
public void componentHidden(ComponentEvent e) { public void componentHidden(ComponentEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
}); });
@@ -116,21 +116,21 @@ public class KLALBClientGUI extends XFrame {
JButton btnNewButton = new JButton("\u6DFB\u52A0"); JButton btnNewButton = new JButton("\u6DFB\u52A0");
btnNewButton.addActionListener(new ActionListener() { btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String s = JOptionPane.showInputDialog(KLALBClientGUI.this, "输入一条线路的地址"); String s = JOptionPane.showInputDialog(KLALBClientGUI.this, "输入一条线路的地址");
if (s != null) { if (s != null) {
if (s.equals("")) { if (s.equals("")) {
JOptionPane.showMessageDialog(KLALBClientGUI.this, "输入不能为空", "错误", JOptionPane.WARNING_MESSAGE); JOptionPane.showMessageDialog(KLALBClientGUI.this, "输入不能为空", "错误", JOptionPane.WARNING_MESSAGE);
} else { } else {
ProcessingFrame psf = new ProcessingFrame("正在下载线路列表"); ProcessingFrame psf = new ProcessingFrame("正在下载线路列表");
psf.setIconImage(bi); psf.setIconImage(bi);
psf.getProgressBar().setIndeterminate(true); psf.getProgressBar().setIndeterminate(true);
psf.setVisible(true); psf.setVisible(true);
ThreadTool.makeVThreadIfSupport("线路列表获取", () -> { ThreadTool.makeVThreadIfSupport("线路列表获取", () -> {
try { try {
KLALBIPList.createIPList(s); KLALBIPList.createIPList(s);
reloadCB(); reloadCB();
} catch (Exception e1) { } catch (Exception e1) {
JOptionPane.showMessageDialog(KLALBClientGUI.this, e1.toString(), "错误", JOptionPane.showMessageDialog(KLALBClientGUI.this, e1.toString(), "错误",
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
e1.printStackTrace(); e1.printStackTrace();
} finally { } finally {
@@ -152,7 +152,7 @@ public class KLALBClientGUI extends XFrame {
t=null; t=null;
return; return;
} }
t=ThreadTool.makeVThreadIfSupport("客户端主线程", () -> { t=ThreadTool.makeVThreadIfSupport("客户端主线程", () -> {
btnNewButton_1.setEnabled(false); btnNewButton_1.setEnabled(false);
comboBox.setEnabled(false); comboBox.setEnabled(false);
String s = (String) comboBox.getSelectedItem(); String s = (String) comboBox.getSelectedItem();
@@ -162,12 +162,10 @@ public class KLALBClientGUI extends XFrame {
File pdis = KLALBIPList.getSLdir(s); File pdis = KLALBIPList.getSLdir(s);
File f = new File(pdis, "iplist.json"); File f = new File(pdis, "iplist.json");
if (f.exists()) { if (f.exists()) {
System.out.println("加载线路列表:" + f); System.out.println("加载线路列表:" + f);;KLALBClient kc=null;
byte[] bytes;KLALBClient kc=null;
try { try {
KLALBIPList.updateIPList(s); KLALBIPList.updateIPList(s);
bytes = Files.readAllBytes(Paths.get(f.toURI())); STJson stj=new STJson(new String(Files.readAllBytes(Paths.get(f.toURI()))));
STJson stj = new STJson(new String(bytes));
kc = new KLALBClient(); kc = new KLALBClient();
kc.getTls().addAll(stj.getTunnels()); kc.getTls().addAll(stj.getTunnels());
List<Tunnel>lt=kc.getTls(); List<Tunnel>lt=kc.getTls();
@@ -206,20 +204,13 @@ public class KLALBClientGUI extends XFrame {
ysp.repaint(); ysp.repaint();
repaint(); repaint();
kc.connectTunnel(); kc.connectTunnel();
List<ServiceElement> lse = stj.getServices();
for (Iterator<ServiceElement> iterator = lse.iterator(); iterator.hasNext();) { ProxyJson pj=new ProxyJson(new File(pdis,"services.json"), stj);
ServiceElement serviceElement = (ServiceElement) iterator.next(); kc.getPet().addAll(pj.getPls());
ProxyIPPortProperties pippp = new ProxyIPPortProperties(pdis, serviceElement.name, kc.listenProxy();
"0.0.0.0", serviceElement.ipport.getPort());
try {
kc.open(pippp.getBindPort(), serviceElement, pippp.getBindIP());
} catch (BindException e) {
System.out.println("打开端口失败:" + pippp.getBindIP() + " " + pippp.getBindPort());
e.printStackTrace();
}
}
btnNewButton_1.setForeground(Color.RED); btnNewButton_1.setForeground(Color.RED);
btnNewButton_1.setText("停止"); btnNewButton_1.setText("停止");
btnNewButton_1.setEnabled(true); btnNewButton_1.setEnabled(true);
while(true) { while(true) {
@@ -234,7 +225,7 @@ public class KLALBClientGUI extends XFrame {
} }
} catch (ConnectException e) { } catch (ConnectException e) {
JOptionPane.showMessageDialog(KLALBClientGUI.this, e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(KLALBClientGUI.this, e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -246,17 +237,17 @@ public class KLALBClientGUI extends XFrame {
} }
} else { } else {
System.out.println("线路列表不存在"); System.out.println("线路列表不存在");
} }
btnNewButton_1.setForeground(Color.GREEN); btnNewButton_1.setForeground(Color.GREEN);
btnNewButton_1.setText("启动"); btnNewButton_1.setText("启动");
btnNewButton_1.setEnabled(true); btnNewButton_1.setEnabled(true);
comboBox.setEnabled(true); comboBox.setEnabled(true);
});t.start(); });t.start();
} }
}); });
panel_1.add(btnNewButton_1, BorderLayout.EAST); panel_1.add(btnNewButton_1, BorderLayout.EAST);
setTitle("KNE云网络负载均衡客户端"); setTitle("KNE云网络负载均衡客户端");
setSize(600, 370); setSize(600, 370);
setLocationRelativeTo(null); setLocationRelativeTo(null);
@@ -267,7 +258,7 @@ public class KLALBClientGUI extends XFrame {
TrayIcon ti = new TrayIcon(bi); TrayIcon ti = new TrayIcon(bi);
ti.setImageAutoSize(true); ti.setImageAutoSize(true);
PopupMenu jpm = new PopupMenu(); PopupMenu jpm = new PopupMenu();
MenuItem mi = new MenuItem("退出"); MenuItem mi = new MenuItem("退出");
mi.addActionListener(new ActionListener() { mi.addActionListener(new ActionListener() {
@Override @Override
@@ -305,4 +296,4 @@ public class KLALBClientGUI extends XFrame {
public static void main(String[] args) { public static void main(String[] args) {
new KLALBClientGUI(); new KLALBClientGUI();
} }
} }
@@ -276,7 +276,7 @@ public class KLALBCore {
for (int i = 0; i < l.size(); i++) { for (int i = 0; i < l.size(); i++) {
KLALBBlock block=l.get(i); KLALBBlock block=l.get(i);
long timex = (System.nanoTime() - block.sendtime) / 1000000; long timex = (System.nanoTime() - block.sendtime) / 1000000;
if (timex > 100*(1<<Math.min(8,block.resend))+1000*i) { if (timex > 200*(1<<Math.min(8,block.resend))+1000*i) {
submitDataBlock(block); submitDataBlock(block);
block.sendtime = System.nanoTime(); block.sendtime = System.nanoTime();
block.resend++; block.resend++;
@@ -284,7 +284,7 @@ public class KLALBCore {
l.remove(i); l.remove(i);
i--; i--;
} }
System.out.println("超时重传:"+block); System.out.println("超时重传:"+block);
} }
} }
} }
@@ -41,7 +41,7 @@ public class KLALBIPList {
String json=KLALBIPList.searchTunnels(address); String json=KLALBIPList.searchTunnels(address);
STJson stj=new STJson(json); STJson stj=new STJson(json);
File f=new File(getSLdir(stj.getName()),"iplist.json"); File f=new File(getSLdir(stj.getName()),"iplist.json");
System.out.println("线路列表已保存到:"+f); System.out.println("线路列表已保存到:"+f);
f.getParentFile().mkdirs(); f.getParentFile().mkdirs();
f.createNewFile(); f.createNewFile();
PrintStream ps=new PrintStream(f); PrintStream ps=new PrintStream(f);
@@ -63,6 +63,6 @@ public class KLALBIPList {
e.printStackTrace(); e.printStackTrace();
} }
} }
throw new ConnectException("搜索地址失败"); throw new ConnectException("搜索地址失败");
} }
} }
+3 -3
View File
@@ -17,11 +17,11 @@ import org.kne.cloud.network.mport.ServiceElement;
public class KLALBSM { public class KLALBSM {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
System.out.println("KNE云负载均衡调度软件服务端V0.1"); System.out.println("KNE云负载均衡调度软件服务端V0.1");
ServerPropties sp=new ServerPropties(); ServerPropties sp=new ServerPropties();
int remp=sp.getPort(); int remp=sp.getPort();
System.out.println("开放端口:"+remp); System.out.println("开放端口:"+remp);
new KLALBServer(remp,new Supplier<String>() { new KLALBServer(remp,new Supplier<String>() {
@Override @Override
@@ -37,7 +37,7 @@ public class KLALBSM {
return sj; return sj;
} }
}); });
System.out.println("提示:运行时输入reload可以重新加载配置文件,已经建立的TCP连接不受影响(暂不支持修改开放端口)"); System.out.println("提示:运行时输入reload可以重新加载配置文件,已经建立的TCP连接不受影响(暂不支持修改开放端口)");
Scanner scn2=new Scanner(System.in); Scanner scn2=new Scanner(System.in);
while(true) { while(true) {
String command=scn2.next(); String command=scn2.next();
@@ -47,7 +47,6 @@ public class KLALBServer {
tcc.setTunnel(tll); tcc.setTunnel(tll);
UUID uid=new UUID(din.readLong(),din.readLong()); UUID uid=new UUID(din.readLong(),din.readLong());
System.out.println(uid);
IOThreadManager nx = null; IOThreadManager nx = null;
synchronized (tcpl) { synchronized (tcpl) {
if(whm.containsKey(uid)) { if(whm.containsKey(uid)) {
@@ -57,9 +56,14 @@ public class KLALBServer {
IOThreadManager n1=nx; IOThreadManager n1=nx;
nx.getCore().setAcceptSYN((b)->{ nx.getCore().setAcceptSYN((b)->{
try { try {
STJson stj=new STJson(gjso.get());
if(!stj.checkSafety(b.lipport)) {
System.out.println("未授权的请求:"+b.lipport);
return false;
}
Socket soc=new Socket(b.lipport.getIp(),b.lipport.getPort()); Socket soc=new Socket(b.lipport.getIp(),b.lipport.getPort());
LocalTCPConnection ltc=new LocalTCPConnection(soc, b.cuid); LocalTCPConnection ltc=new LocalTCPConnection(soc, b.cuid);
ThreadTool.makeVThreadIfSupport("局域网连接监视线程", ()->{ ThreadTool.makeVThreadIfSupport("局域网连接监视线程", ()->{
try { try {
n1.handleLocal(ltc, false); n1.handleLocal(ltc, false);
}finally { }finally {
@@ -68,7 +72,7 @@ public class KLALBServer {
}).start(); }).start();
return true; return true;
} catch (IOException e) { } catch (IOException e) {
System.out.println("连接本地服务"+b.lipport+"失败,请检查你的本地服务"); System.out.println("连接本地服务"+b.lipport+"失败,请检查你的本地服务");
e.printStackTrace(); e.printStackTrace();
} }
return false; return false;
@@ -0,0 +1,46 @@
package org.kne.cloud.network.klalb;
import java.util.Objects;
import org.kne.cloud.network.mport.IPPort;
import org.kne.cloud.network.mport.ServiceElement;
public class ProxyElement {
private ServiceElement se;
private IPPort ipport;
public ServiceElement getSe() {
return se;
}
public IPPort getIpport() {
return ipport;
}
@Override
public int hashCode() {
return Objects.hash(ipport, se);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ProxyElement other = (ProxyElement) obj;
return Objects.equals(ipport, other.ipport) && Objects.equals(se, other.se);
}
public ProxyElement(ServiceElement se, IPPort ipport) {
super();
this.se = se;
this.ipport = ipport;
}
public ProxyElement() {
}
public void setSe(ServiceElement se) {
this.se = se;
}
public void setIpport(IPPort ipport) {
this.ipport = ipport;
}
}
@@ -0,0 +1,101 @@
package org.kne.cloud.network.klalb;
import java.io.*;
import java.util.*;
import org.kne.cloud.network.mport.IPPort;
import org.kne.cloud.network.mport.ServiceElement;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
public class ProxyJson {
private File f;
private List<ProxyElement> pls=new ArrayList<>();
public List<ProxyElement> getPls() {
return pls;
}
public ProxyJson(File f,STJson def) throws IOException {
super();
this.f = f;
if(!f.exists()||f.length()==0l) {
f.createNewFile();
JsonWriter jw=null;
try {
jw=new JsonWriter(new FileWriter(f));
jw.setIndent(" ");
jw.beginObject();
jw.name("services");
jw.beginArray();
for (Iterator<ServiceElement> iterator = def.getServices().iterator(); iterator.hasNext();) {
ServiceElement proxye = (ServiceElement) iterator.next();
jw.beginObject();
jw.name("name");
jw.value(proxye.name);
jw.name("protocol");
jw.value(proxye.protocol);
jw.name("localaddress");
jw.value(proxye.ipport.toString());
jw.name("bindaddress");
jw.value("0.0.0.0:"+proxye.ipport.getPort());
jw.endObject();
}
jw.endArray();
jw.endObject();
}finally{
if(jw!=null)
jw.close();
}
}
JsonReader jr=null;
try {
jr=new JsonReader(new FileReader(f));
jr.beginObject();
while(jr.hasNext()) {
String name=jr.nextName();
switch(name) {
case "services":
jr.beginArray();
while(jr.hasNext()) {
jr.beginObject();
ProxyElement pe=new ProxyElement();
ServiceElement se=new ServiceElement();
pe.setSe(se);
while(jr.hasNext()) {
String n3=jr.nextName();
switch(n3) {
case "name":
se.name=jr.nextString();
break;
case "protocol":
se.protocol=jr.nextString();
break;
case "localaddress":
se.ipport=new IPPort (jr.nextString());
break;
case "bindaddress":
pe.setIpport(new IPPort (jr.nextString()));
break;
default:
jr.skipValue();
break;
}
}
pls.add(pe);
jr.endObject();
}
jr.endArray();
break;
default:
jr.skipValue();
break;
}
}
jr.endObject();
}finally {
if(jr!=null)
jr.close();
}
}
}
@@ -61,6 +61,16 @@ public class STJson {
t.setName(sr.nextString()); t.setName(sr.nextString());
} else if (n2.equals("remoteaddress")) { } else if (n2.equals("remoteaddress")) {
t.setIpport(new IPPort( sr.nextString())); t.setIpport(new IPPort( sr.nextString()));
} else if (n2.equals("frpc")) {
StringBuilder sbd=new StringBuilder();
sr.beginArray();
while(sr.hasNext()) {
sbd.append(sr.nextString());
sbd.append('\r');
sbd.append('\n');
}
sr.endArray();
t.setFrpc(sbd.toString());
} else{ } else{
sr.skipValue(); sr.skipValue();
} }
@@ -81,4 +91,14 @@ public class STJson {
return name; return name;
} }
public boolean checkSafety(IPPort lipport) {
for (Iterator iterator = services.iterator(); iterator.hasNext();) {
ServiceElement serviceElement = (ServiceElement) iterator.next();
if(lipport.equals(serviceElement.ipport)) {
return true;
}
}
return false;
}
} }
@@ -32,21 +32,21 @@ public class TCPConnection {
if (din != null) if (din != null)
din.close(); din.close();
} catch (IOException e1) { } catch (IOException e1) {
// TODO 自动生成的 catch // TODO 自动生成的 catch
e1.printStackTrace(); e1.printStackTrace();
} }
try { try {
if (dout != null) if (dout != null)
dout.close(); dout.close();
} catch (IOException e1) { } catch (IOException e1) {
// TODO 自动生成的 catch // TODO 自动生成的 catch
e1.printStackTrace(); e1.printStackTrace();
} }
try { try {
if (connect != null) if (connect != null)
connect.close(); connect.close();
} catch (IOException e) { } catch (IOException e) {
// TODO 自动生成的 catch // TODO 自动生成的 catch
e.printStackTrace(); e.printStackTrace();
} }
connect = null; connect = null;
@@ -21,7 +21,7 @@ public class TCPListener {
while(flag){ while(flag){
try { try {
Socket soce=servers.accept(); Socket soce=servers.accept();
ThreadTool.makeVThreadIfSupport("śËżÚźŕĚýĎßłĚ",()->{ ThreadTool.makeVThreadIfSupport("端口监听线程",()->{
con.accept(soce); con.accept(soce);
}).start(); }).start();
} catch (IOException e) { } catch (IOException e) {
+2 -2
View File
@@ -32,11 +32,11 @@ public class TPanel extends JPanel{
setLayout(new BorderLayout(0, 0)); setLayout(new BorderLayout(0, 0));
tname = new JLabel(name); tname = new JLabel(name);
tname.setFont(new Font("ËÎÌå", Font.BOLD, 20)); tname.setFont(new Font("宋体", Font.BOLD, 20));
add(tname, BorderLayout.WEST); add(tname, BorderLayout.WEST);
targ = new JLabel(); targ = new JLabel();
targ.setFont(new Font("ËÎÌå", Font.PLAIN, 13)); targ.setFont(new Font("宋体", Font.PLAIN, 13));
targ.setHorizontalAlignment(SwingConstants.TRAILING); targ.setHorizontalAlignment(SwingConstants.TRAILING);
targ.setForeground(Color.YELLOW); targ.setForeground(Color.YELLOW);
add(targ, BorderLayout.CENTER); add(targ, BorderLayout.CENTER);
+95 -5
View File
@@ -2,10 +2,13 @@ package org.kne.cloud.network.klalb;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream; import java.io.PrintStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
@@ -19,6 +22,7 @@ import java.util.Set;
import java.util.Vector; import java.util.Vector;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
@@ -30,6 +34,34 @@ import org.kne.cloud.network.mport.IPPort;
public class Tunnel{ public class Tunnel{
private String name; private String name;
private IPPort ipport; private IPPort ipport;
private String frpc;
public String getFrpc() {
return frpc;
}
private Thread hook;
public void setFrpc(String frpc) {
this.frpc = frpc;
if(frpc!=null&&hook==null) {
hook=new Thread(()->{
finalize();
});
Runtime.getRuntime().addShutdownHook(hook);
}
}
@Override
protected void finalize() {
if(hook!=null) {
try {
Runtime.getRuntime().removeShutdownHook(hook);
}catch(Exception e) {
}
if(p!=null) {
System.out.println("frpc已关闭");
p.destroy();
}
}
}
private boolean state=false; private boolean state=false;
private TListener tlr; private TListener tlr;
@@ -87,9 +119,62 @@ public class Tunnel{
public String toString() { public String toString() {
return getName()+"$"+getIpport()+" "+delay/1000000; return getName()+"$"+getIpport()+" "+delay/1000000;
} }
private volatile Process p=null;
public Socket connectClientSocket() throws UnknownHostException, IOException { public Socket connectClientSocket() throws UnknownHostException, IOException {
if(frpc!=null) {
File f=new File("frpc");
f.mkdirs();
File inif=new File(f,"frpc.ini");
inif.createNewFile();
PrintStream ps=new PrintStream(inif);
ps.print(frpc);
ps.close();
AtomicBoolean ab=new AtomicBoolean(false);
Object lock=new Object();
if(p==null)
new Thread(()->{
try {
p = Runtime.getRuntime().exec("./frpc/frpc_windows_386.exe",null,f);
BufferedReader brd=new BufferedReader(new InputStreamReader( p.getInputStream()));
while(true) {
String r=brd.readLine();
if(r==null)
break;
System.err.println(r);
if(r.contains("start visitor success")) {
synchronized (lock) {
lock.notifyAll();
}
return;
}
}
ab.set(true);
synchronized (lock) {
lock.notifyAll();
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(ab.get()) {
throw new IOException("frpc ERROR");
}
}
Socket socket=new Socket(); Socket socket=new Socket();
// socket.bind(new InetSocketAddress(new Random().nextInt(65535)+1));
socket.connect(getIpport().getSocketAddress(), Consts.CONNECT_TIMEOUT); socket.connect(getIpport().getSocketAddress(), Consts.CONNECT_TIMEOUT);
return socket; return socket;
} }
@@ -140,22 +225,27 @@ public class Tunnel{
public AtomicLong getIM() { public AtomicLong getIM() {
return im; return im;
} }
PrintStream ndbg=null; /*PrintStream ndbg=null;
private void initcdbg() { private void initcdbg() {
try { try {
ndbg=new PrintStream(name+".csv"); ndbg=new PrintStream(name+".csv");
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }*/
public void updateTraffics(long timems) { public void updateTraffics(long timems) {
tlr.setTraffic(om.get(), im.get(), om.get()-om1, im.get()-im1); tlr.setTraffic(om.get(), im.get(), om.get()-om1, im.get()-im1);
/*
if(ndbg==null) if(ndbg==null)
initcdbg(); initcdbg();
ndbg.println((om.get()-om1)+ (im.get()-im1)+","+delay); ndbg.println((om.get()-om1)+ (im.get()-im1)+","+delay);
*/
om1=om.get(); om1=om.get();
im1=im.get(); im1=im.get();
} }
public void destroyFrpc() {
if(p!=null) {
p.destroy();
}
}
} }
@@ -22,8 +22,8 @@ public class PortMultiUse {
} }
Scanner scn=new Scanner(f); Scanner scn=new Scanner(f);
int remp=scn.nextInt(); int remp=scn.nextInt();
System.out.println("端口复用程序V0.2"); System.out.println("端口复用程序V0.2");
System.out.println("开放端口:"+remp); System.out.println("开放端口:"+remp);
while(scn.hasNext() ) { while(scn.hasNext() ) {
String s=scn.next(); String s=scn.next();
ServiceElement se=new ServiceElement(s); ServiceElement se=new ServiceElement(s);
@@ -32,7 +32,7 @@ public class PortMultiUse {
} }
scn.close(); scn.close();
new PortRelay(remp,services).start(); new PortRelay(remp,services).start();
System.out.println("提示:运行时输入reload可以重新加载配置文件,已经建立的TCP连接不受影响(暂不支持修改开放端口)"); System.out.println("提示:运行时输入reload可以重新加载配置文件,已经建立的TCP连接不受影响(暂不支持修改开放端口)");
Scanner scn2=new Scanner(System.in); Scanner scn2=new Scanner(System.in);
while(true) { while(true) {
String command=scn2.next(); String command=scn2.next();
@@ -56,16 +56,16 @@ public class PortMultiUse {
} }
private static void ept() { private static void ept() {
System.out.println("请填写配置文件后再启动程序!"); System.out.println("请填写配置文件后再启动程序!");
System.out.println("格式:"); System.out.println("格式:");
System.out.println("开放端口"); System.out.println("开放端口");
System.out.println("服务协议1$服务地址1$服务端口1"); System.out.println("服务协议1$服务地址1$服务端口1");
System.out.println("服务协议2$服务地址2$服务端口2"); System.out.println("服务协议2$服务地址2$服务端口2");
System.out.println("......"); System.out.println("......");
System.out.println("服务协议n$服务地址n$服务端口n"); System.out.println("服务协议n$服务地址n$服务端口n");
System.out.println("默认服务地址$默认服务端口"); System.out.println("默认服务地址$默认服务端口");
System.out.println(""); System.out.println("");
System.out.println("按照顺序从上向下匹配,若都不是则匹配最后一个"); System.out.println("按照顺序从上向下匹配,若都不是则匹配最后一个");
} }
} }
@@ -17,7 +17,7 @@ public class PortRelay {
this.services = services; this.services = services;
this.port = port; this.port = port;
ssc=new TCPListener(port); ssc=new TCPListener(port);
System.out.println("已打开端口:" + port); System.out.println("已打开端口:" + port);
} }
public void start() throws IOException { public void start() throws IOException {
ssc.setCon((s)->{ ssc.setCon((s)->{
@@ -44,7 +44,7 @@ public class PortRelay {
dinl=xdinl; dinl=xdinl;
final DataOutputStream xdoutl =new DataOutputStream(sl.getOutputStream()); final DataOutputStream xdoutl =new DataOutputStream(sl.getOutputStream());
doutl=xdoutl; doutl=xdoutl;
Thread tl=ThreadTool.makeVThreadIfSupport("远程->本地 转发线程", ()->{ Thread tl=ThreadTool.makeVThreadIfSupport("远程->本地 转发线程", ()->{
try { try {
xdoutl.writeShort(n); xdoutl.writeShort(n);
int len; int len;
@@ -67,7 +67,7 @@ public class PortRelay {
} }
} }
}); });
Thread tr=ThreadTool.makeVThreadIfSupport("本地->远程 转发线程", ()->{ Thread tr=ThreadTool.makeVThreadIfSupport("本地->远程 转发线程", ()->{
try { try {
int len; int len;
byte[]b=new byte[8192]; byte[]b=new byte[8192];
@@ -80,7 +80,7 @@ public class PortRelay {
try { try {
xdinl.close(); xdinl.close();
} catch (IOException e) { } catch (IOException e) {
// TODO 自动生成的 catch // TODO 自动生成的 catch
e.printStackTrace(); e.printStackTrace();
} }
if(xdout!=null) if(xdout!=null)
@@ -38,7 +38,7 @@ public class ServiceElement {
} }
} }
public ServiceElement() { public ServiceElement() {
// TODO 自动生成的构造函数存根 // TODO 自动生成的构造函数存根
} }
@Override @Override
public String toString() { public String toString() {
@@ -17,7 +17,7 @@ public class TCPListener {
while(flag){ while(flag){
try { try {
Socket soce=servers.accept(); Socket soce=servers.accept();
ThreadTool.makeVThreadIfSupport("śËżÚźŕĚýĎßłĚ",()->{ ThreadTool.makeVThreadIfSupport("端口监听线程",()->{
con.accept(soce); con.accept(soce);
}).start(); }).start();
} catch (IOException e) { } catch (IOException e) {
@@ -21,7 +21,7 @@ public class ThreadTool {
}catch(Throwable e) { }catch(Throwable e) {
//e.printStackTrace(); //e.printStackTrace();
if(first) { if(first) {
System.out.println("请使用java19以上版本以提高性能!"); System.out.println("请使用java19以上版本以提高性能!");
first=false; first=false;
} }
return new Thread(r, name); return new Thread(r, name);
+31 -31
View File
@@ -31,7 +31,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -51,19 +51,19 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
}; };
@@ -172,7 +172,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -200,7 +200,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -228,7 +228,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -255,7 +255,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -282,7 +282,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -310,7 +310,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -338,7 +338,7 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -378,25 +378,25 @@ public class XFrame extends JFrame {
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
}); });
@@ -436,25 +436,25 @@ public class XFrame extends JFrame {
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
}); });
@@ -474,31 +474,31 @@ public class XFrame extends JFrame {
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseExited(MouseEvent e) { public void mouseExited(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
int s=XFrame.this.getExtendedState(); int s=XFrame.this.getExtendedState();
if(s!=JFrame.ICONIFIED) { if(s!=JFrame.ICONIFIED) {
state=s; state=s;
@@ -513,7 +513,7 @@ public class XFrame extends JFrame {
titlelabel = new JLabel(); titlelabel = new JLabel();
sl_titlepanel.putConstraint(SpringLayout.WEST, titlelabel, 31, SpringLayout.WEST, titlepanel); sl_titlepanel.putConstraint(SpringLayout.WEST, titlelabel, 31, SpringLayout.WEST, titlepanel);
sl_titlepanel.putConstraint(SpringLayout.EAST, titlelabel, -31, SpringLayout.EAST, titlepanel); sl_titlepanel.putConstraint(SpringLayout.EAST, titlelabel, -31, SpringLayout.EAST, titlepanel);
titlelabel.setFont(new Font("宋体", Font.PLAIN, 16)); titlelabel.setFont(new Font("宋体", Font.PLAIN, 16));
sl_titlepanel.putConstraint(SpringLayout.NORTH, titlelabel, 0, SpringLayout.NORTH, titlepanel); sl_titlepanel.putConstraint(SpringLayout.NORTH, titlelabel, 0, SpringLayout.NORTH, titlepanel);
sl_titlepanel.putConstraint(SpringLayout.SOUTH, titlelabel, 0, SpringLayout.SOUTH, titlepanel); sl_titlepanel.putConstraint(SpringLayout.SOUTH, titlelabel, 0, SpringLayout.SOUTH, titlepanel);
titlelabel.setOpaque(false); titlelabel.setOpaque(false);
@@ -528,13 +528,13 @@ public class XFrame extends JFrame {
@Override @Override
public void windowOpened(WindowEvent e) { public void windowOpened(WindowEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void windowIconified(WindowEvent e) { public void windowIconified(WindowEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@@ -546,25 +546,25 @@ public class XFrame extends JFrame {
@Override @Override
public void windowDeactivated(WindowEvent e) { public void windowDeactivated(WindowEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void windowClosed(WindowEvent e) { public void windowClosed(WindowEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void windowActivated(WindowEvent e) { public void windowActivated(WindowEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
}); });
+2 -2
View File
@@ -102,13 +102,13 @@ settings.addContainerListener(new ContainerListener() {
@Override @Override
public void componentMoved(ComponentEvent e) { public void componentMoved(ComponentEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
@Override @Override
public void componentHidden(ComponentEvent e) { public void componentHidden(ComponentEvent e) {
// TODO 自动生成的方法存根 // TODO 自动生成的方法存根
} }
}); });
+1 -1
View File
@@ -32,7 +32,7 @@ public class UIEnv {
} catch (FontFormatException e1) { } catch (FontFormatException e1) {
e1.printStackTrace(); e1.printStackTrace();
} catch (IOException e1) { } catch (IOException e1) {
// TODO 自动生成的 catch // TODO 自动生成的 catch
e1.printStackTrace(); e1.printStackTrace();
} }