commit b7aa648e0350380ab085b57035e38f814688735a
Author: Olof Larsson
Date: Wed Apr 6 21:43:57 2011 +0200
first commit
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..e040f58
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2e706a0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,19 @@
+# Eclipse stuff
+/.classpath
+/.project
+/.settings
+
+# netbeans
+/nbproject
+
+# vim
+.*.sw[a-p]
+
+# various other potential build files
+/build
+/bin
+/dist
+/localexport.jardesc
+
+# Mac filesystem dust
+.DS_Store
\ No newline at end of file
diff --git a/.project b/.project
new file mode 100644
index 0000000..e0d9b68
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ AncientGates
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..a4b9403
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Wed Apr 06 16:59:25 CEST 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/LGPL.txt b/LGPL.txt
new file mode 100644
index 0000000..65c5ca8
--- /dev/null
+++ b/LGPL.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/LICENCE.txt b/LICENCE.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/LICENCE.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..712fee3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+AncientGates - Minimalistic and Powerfull Portal-Gates
+====================
+With this plugin the server administrators can create gates that will teleport anyone who enter to a location specific to that gate.
+You may design the gates any way you like! Build your gate of dirt if you feel like it :)
+
+Try the ingame command /gate
+for more info.
+
+Usage
+---------
+Read the full userguide here: [http://mcteam.org/ancientgates](http://mcteam.org/ancientgates)
+
+Installing
+----------
+1. Download the latest release: [https://github.com/oloflarsson/AncientGates/downloads](https://github.com/oloflarsson/AncientGates/downloads)
+1. Put AncientGates.jar in the plugins folder.
+
+License
+----------
+This project has a LGPL license just like the Bukkit project.
+This project uses [GSON](http://code.google.com/p/google-gson/) which has a [Apache 2.0 license](http://www.apache.org/licenses/LICENSE-2.0 ).
\ No newline at end of file
diff --git a/bin/org/mcteam/ancientgates/Conf.class b/bin/org/mcteam/ancientgates/Conf.class
new file mode 100644
index 0000000..c91ea4e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/Conf.class differ
diff --git a/bin/org/mcteam/ancientgates/Gate$1.class b/bin/org/mcteam/ancientgates/Gate$1.class
new file mode 100644
index 0000000..8eba156
Binary files /dev/null and b/bin/org/mcteam/ancientgates/Gate$1.class differ
diff --git a/bin/org/mcteam/ancientgates/Gate.class b/bin/org/mcteam/ancientgates/Gate.class
new file mode 100644
index 0000000..9e3909e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/Gate.class differ
diff --git a/bin/org/mcteam/ancientgates/MyLocationTypeAdapter.class b/bin/org/mcteam/ancientgates/MyLocationTypeAdapter.class
new file mode 100644
index 0000000..8923ce1
Binary files /dev/null and b/bin/org/mcteam/ancientgates/MyLocationTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/Plugin.class b/bin/org/mcteam/ancientgates/Plugin.class
new file mode 100644
index 0000000..f2f830f
Binary files /dev/null and b/bin/org/mcteam/ancientgates/Plugin.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/BaseCommand.class b/bin/org/mcteam/ancientgates/commands/BaseCommand.class
new file mode 100644
index 0000000..cfed904
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/BaseCommand.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandClose.class b/bin/org/mcteam/ancientgates/commands/CommandClose.class
new file mode 100644
index 0000000..cd7d60c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandClose.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandCreate.class b/bin/org/mcteam/ancientgates/commands/CommandCreate.class
new file mode 100644
index 0000000..938289b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandCreate.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandDelete.class b/bin/org/mcteam/ancientgates/commands/CommandDelete.class
new file mode 100644
index 0000000..e6f866a
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandDelete.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandHelp.class b/bin/org/mcteam/ancientgates/commands/CommandHelp.class
new file mode 100644
index 0000000..f8ed79c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandHelp.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandList.class b/bin/org/mcteam/ancientgates/commands/CommandList.class
new file mode 100644
index 0000000..bc13f9b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandList.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandOpen.class b/bin/org/mcteam/ancientgates/commands/CommandOpen.class
new file mode 100644
index 0000000..09558ec
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandOpen.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandSetFrom.class b/bin/org/mcteam/ancientgates/commands/CommandSetFrom.class
new file mode 100644
index 0000000..1740b90
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandSetFrom.class differ
diff --git a/bin/org/mcteam/ancientgates/commands/CommandSetTo.class b/bin/org/mcteam/ancientgates/commands/CommandSetTo.class
new file mode 100644
index 0000000..729c777
Binary files /dev/null and b/bin/org/mcteam/ancientgates/commands/CommandSetTo.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/AnonymousAndLocalClassExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/AnonymousAndLocalClassExclusionStrategy.class
new file mode 100644
index 0000000..ebe9b04
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/AnonymousAndLocalClassExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Cache.class b/bin/org/mcteam/ancientgates/gson/Cache.class
new file mode 100644
index 0000000..b0a97cd
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Cache.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/CamelCaseSeparatorNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/CamelCaseSeparatorNamingPolicy.class
new file mode 100644
index 0000000..6d5d0d8
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/CamelCaseSeparatorNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/CircularReferenceException.class b/bin/org/mcteam/ancientgates/gson/CircularReferenceException.class
new file mode 100644
index 0000000..06a2cc9
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/CircularReferenceException.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/CompositionFieldNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/CompositionFieldNamingPolicy.class
new file mode 100644
index 0000000..3e20707
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/CompositionFieldNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BigDecimalTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BigDecimalTypeAdapter.class
new file mode 100644
index 0000000..0f7b803
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BigDecimalTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BigIntegerTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BigIntegerTypeAdapter.class
new file mode 100644
index 0000000..db6e994
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BigIntegerTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BooleanTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BooleanTypeAdapter.class
new file mode 100644
index 0000000..eb217f4
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$BooleanTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$ByteTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$ByteTypeAdapter.class
new file mode 100644
index 0000000..38f18b8
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$ByteTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$CharacterTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$CharacterTypeAdapter.class
new file mode 100644
index 0000000..4710322
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$CharacterTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$CollectionTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$CollectionTypeAdapter.class
new file mode 100644
index 0000000..6baab76
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$CollectionTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultDateTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultDateTypeAdapter.class
new file mode 100644
index 0000000..e8622f5
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultDateTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultJavaSqlDateTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultJavaSqlDateTypeAdapter.class
new file mode 100644
index 0000000..666d71d
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultJavaSqlDateTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultTimeTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultTimeTypeAdapter.class
new file mode 100644
index 0000000..f00d062
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultTimeTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultTimestampDeserializer.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultTimestampDeserializer.class
new file mode 100644
index 0000000..a87cbd2
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DefaultTimestampDeserializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DoubleDeserializer.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DoubleDeserializer.class
new file mode 100644
index 0000000..1c6c9b6
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DoubleDeserializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DoubleSerializer.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DoubleSerializer.class
new file mode 100644
index 0000000..c2c0e5b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$DoubleSerializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$EnumTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$EnumTypeAdapter.class
new file mode 100644
index 0000000..fc891c1
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$EnumTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$FloatDeserializer.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$FloatDeserializer.class
new file mode 100644
index 0000000..513af6d
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$FloatDeserializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$FloatSerializer.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$FloatSerializer.class
new file mode 100644
index 0000000..9014ddc
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$FloatSerializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$GregorianCalendarTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$GregorianCalendarTypeAdapter.class
new file mode 100644
index 0000000..116b114
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$GregorianCalendarTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$HashSetCreator.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$HashSetCreator.class
new file mode 100644
index 0000000..9d52f65
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$HashSetCreator.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$IntegerTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$IntegerTypeAdapter.class
new file mode 100644
index 0000000..93b96fb
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$IntegerTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LocaleTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LocaleTypeAdapter.class
new file mode 100644
index 0000000..250a6dc
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LocaleTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LongDeserializer.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LongDeserializer.class
new file mode 100644
index 0000000..1d025ad
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LongDeserializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LongSerializer.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LongSerializer.class
new file mode 100644
index 0000000..6123ae2
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$LongSerializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$MapTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$MapTypeAdapter.class
new file mode 100644
index 0000000..fcf1133
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$MapTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$NumberTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$NumberTypeAdapter.class
new file mode 100644
index 0000000..539213c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$NumberTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$PropertiesCreator.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$PropertiesCreator.class
new file mode 100644
index 0000000..097cf77
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$PropertiesCreator.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$ShortTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$ShortTypeAdapter.class
new file mode 100644
index 0000000..81fad79
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$ShortTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$StringTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$StringTypeAdapter.class
new file mode 100644
index 0000000..a2cec86
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$StringTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$TreeSetCreator.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$TreeSetCreator.class
new file mode 100644
index 0000000..b1ec5e9
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$TreeSetCreator.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UriTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UriTypeAdapter.class
new file mode 100644
index 0000000..2cc8d3e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UriTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UrlTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UrlTypeAdapter.class
new file mode 100644
index 0000000..6af5bb6
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UrlTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UuidTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UuidTypeAdapter.class
new file mode 100644
index 0000000..ea395b8
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters$UuidTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters.class b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters.class
new file mode 100644
index 0000000..e0736f2
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DefaultTypeAdapters.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DelegatingJsonElementVisitor.class b/bin/org/mcteam/ancientgates/gson/DelegatingJsonElementVisitor.class
new file mode 100644
index 0000000..ea4f393
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DelegatingJsonElementVisitor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/DisjunctionExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/DisjunctionExclusionStrategy.class
new file mode 100644
index 0000000..a4478be
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/DisjunctionExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Escaper.class b/bin/org/mcteam/ancientgates/gson/Escaper.class
new file mode 100644
index 0000000..bfe683b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Escaper.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/ExclusionStrategy.class
new file mode 100644
index 0000000..851c34e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ExposeAnnotationDeserializationExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/ExposeAnnotationDeserializationExclusionStrategy.class
new file mode 100644
index 0000000..cf6ac61
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ExposeAnnotationDeserializationExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ExposeAnnotationSerializationExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/ExposeAnnotationSerializationExclusionStrategy.class
new file mode 100644
index 0000000..6b8ab65
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ExposeAnnotationSerializationExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/FieldAttributes.class b/bin/org/mcteam/ancientgates/gson/FieldAttributes.class
new file mode 100644
index 0000000..378238b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/FieldAttributes.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/FieldNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/FieldNamingPolicy.class
new file mode 100644
index 0000000..d3127c3
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/FieldNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy.class b/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy.class
new file mode 100644
index 0000000..4998ee4
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy2.class b/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy2.class
new file mode 100644
index 0000000..7aab950
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy2.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy2Adapter.class b/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy2Adapter.class
new file mode 100644
index 0000000..d97d564
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/FieldNamingStrategy2Adapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/GenericArrayTypeImpl.class b/bin/org/mcteam/ancientgates/gson/GenericArrayTypeImpl.class
new file mode 100644
index 0000000..07e9435
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/GenericArrayTypeImpl.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Gson.class b/bin/org/mcteam/ancientgates/gson/Gson.class
new file mode 100644
index 0000000..a44d9ad
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Gson.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/GsonBuilder.class b/bin/org/mcteam/ancientgates/gson/GsonBuilder.class
new file mode 100644
index 0000000..c4c3302
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/GsonBuilder.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/InnerClassExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/InnerClassExclusionStrategy.class
new file mode 100644
index 0000000..d2cb98e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/InnerClassExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/InstanceCreator.class b/bin/org/mcteam/ancientgates/gson/InstanceCreator.class
new file mode 100644
index 0000000..ca0da37
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/InstanceCreator.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JavaFieldNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/JavaFieldNamingPolicy.class
new file mode 100644
index 0000000..5a3c19a
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JavaFieldNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonArray.class b/bin/org/mcteam/ancientgates/gson/JsonArray.class
new file mode 100644
index 0000000..7b0db8a
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonArray.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonArrayDeserializationVisitor.class b/bin/org/mcteam/ancientgates/gson/JsonArrayDeserializationVisitor.class
new file mode 100644
index 0000000..08978ef
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonArrayDeserializationVisitor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonDeserializationContext.class b/bin/org/mcteam/ancientgates/gson/JsonDeserializationContext.class
new file mode 100644
index 0000000..b87df80
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonDeserializationContext.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonDeserializationContextDefault.class b/bin/org/mcteam/ancientgates/gson/JsonDeserializationContextDefault.class
new file mode 100644
index 0000000..75a3ef9
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonDeserializationContextDefault.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonDeserializationVisitor.class b/bin/org/mcteam/ancientgates/gson/JsonDeserializationVisitor.class
new file mode 100644
index 0000000..34e663a
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonDeserializationVisitor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonDeserializer.class b/bin/org/mcteam/ancientgates/gson/JsonDeserializer.class
new file mode 100644
index 0000000..9c22966
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonDeserializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonDeserializerExceptionWrapper.class b/bin/org/mcteam/ancientgates/gson/JsonDeserializerExceptionWrapper.class
new file mode 100644
index 0000000..cd789d9
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonDeserializerExceptionWrapper.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonElement.class b/bin/org/mcteam/ancientgates/gson/JsonElement.class
new file mode 100644
index 0000000..9c177b8
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonElement.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonElementVisitor.class b/bin/org/mcteam/ancientgates/gson/JsonElementVisitor.class
new file mode 100644
index 0000000..173e304
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonElementVisitor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonFieldNameValidator.class b/bin/org/mcteam/ancientgates/gson/JsonFieldNameValidator.class
new file mode 100644
index 0000000..fcc862b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonFieldNameValidator.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonIOException.class b/bin/org/mcteam/ancientgates/gson/JsonIOException.class
new file mode 100644
index 0000000..b417721
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonIOException.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonNull.class b/bin/org/mcteam/ancientgates/gson/JsonNull.class
new file mode 100644
index 0000000..e6834d1
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonNull.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonObject.class b/bin/org/mcteam/ancientgates/gson/JsonObject.class
new file mode 100644
index 0000000..cb1f876
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonObject.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonObjectDeserializationVisitor.class b/bin/org/mcteam/ancientgates/gson/JsonObjectDeserializationVisitor.class
new file mode 100644
index 0000000..7cfd97d
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonObjectDeserializationVisitor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonParseException.class b/bin/org/mcteam/ancientgates/gson/JsonParseException.class
new file mode 100644
index 0000000..a78a7d7
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonParseException.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonParser.class b/bin/org/mcteam/ancientgates/gson/JsonParser.class
new file mode 100644
index 0000000..ff1ab07
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonParser.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonPrimitive.class b/bin/org/mcteam/ancientgates/gson/JsonPrimitive.class
new file mode 100644
index 0000000..555de25
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonPrimitive.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonSerializationContext.class b/bin/org/mcteam/ancientgates/gson/JsonSerializationContext.class
new file mode 100644
index 0000000..d29d442
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonSerializationContext.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonSerializationContextDefault.class b/bin/org/mcteam/ancientgates/gson/JsonSerializationContextDefault.class
new file mode 100644
index 0000000..68f70cb
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonSerializationContextDefault.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonSerializationVisitor.class b/bin/org/mcteam/ancientgates/gson/JsonSerializationVisitor.class
new file mode 100644
index 0000000..b7f9922
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonSerializationVisitor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonSerializer.class b/bin/org/mcteam/ancientgates/gson/JsonSerializer.class
new file mode 100644
index 0000000..b111a31
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonSerializer.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonStreamParser.class b/bin/org/mcteam/ancientgates/gson/JsonStreamParser.class
new file mode 100644
index 0000000..81ee818
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonStreamParser.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonSyntaxException.class b/bin/org/mcteam/ancientgates/gson/JsonSyntaxException.class
new file mode 100644
index 0000000..770437f
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonSyntaxException.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/JsonTreeNavigator.class b/bin/org/mcteam/ancientgates/gson/JsonTreeNavigator.class
new file mode 100644
index 0000000..ea151c0
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/JsonTreeNavigator.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$DefaultStrategy.class b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$DefaultStrategy.class
new file mode 100644
index 0000000..94eff22
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$DefaultStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$Strategy.class b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$Strategy.class
new file mode 100644
index 0000000..929d4b4
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$Strategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$StringStrategy.class b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$StringStrategy.class
new file mode 100644
index 0000000..cad844d
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy$StringStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy.class b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy.class
new file mode 100644
index 0000000..453a9f3
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/LongSerializationPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/LowerCamelCaseSeparatorNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/LowerCamelCaseSeparatorNamingPolicy.class
new file mode 100644
index 0000000..654e706
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/LowerCamelCaseSeparatorNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/LowerCaseNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/LowerCaseNamingPolicy.class
new file mode 100644
index 0000000..eb7b0b1
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/LowerCaseNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/LruCache.class b/bin/org/mcteam/ancientgates/gson/LruCache.class
new file mode 100644
index 0000000..1ce4ca3
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/LruCache.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/MapAsArrayTypeAdapter.class b/bin/org/mcteam/ancientgates/gson/MapAsArrayTypeAdapter.class
new file mode 100644
index 0000000..61298d5
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/MapAsArrayTypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/MappedObjectConstructor.class b/bin/org/mcteam/ancientgates/gson/MappedObjectConstructor.class
new file mode 100644
index 0000000..71dab39
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/MappedObjectConstructor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/MemoryRefStack.class b/bin/org/mcteam/ancientgates/gson/MemoryRefStack.class
new file mode 100644
index 0000000..57df97c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/MemoryRefStack.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ModifierBasedExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/ModifierBasedExclusionStrategy.class
new file mode 100644
index 0000000..bd1fd1e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ModifierBasedExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy$LetterModifier.class b/bin/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy$LetterModifier.class
new file mode 100644
index 0000000..af9ea08
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy$LetterModifier.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy.class
new file mode 100644
index 0000000..d467acb
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/NullExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/NullExclusionStrategy.class
new file mode 100644
index 0000000..09f8586
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/NullExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ObjectConstructor.class b/bin/org/mcteam/ancientgates/gson/ObjectConstructor.class
new file mode 100644
index 0000000..7d1d21d
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ObjectConstructor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ObjectNavigator$Visitor.class b/bin/org/mcteam/ancientgates/gson/ObjectNavigator$Visitor.class
new file mode 100644
index 0000000..aab202e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ObjectNavigator$Visitor.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ObjectNavigator.class b/bin/org/mcteam/ancientgates/gson/ObjectNavigator.class
new file mode 100644
index 0000000..aa4ebff
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ObjectNavigator.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ObjectNavigatorFactory.class b/bin/org/mcteam/ancientgates/gson/ObjectNavigatorFactory.class
new file mode 100644
index 0000000..47c3f71
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ObjectNavigatorFactory.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ObjectTypePair.class b/bin/org/mcteam/ancientgates/gson/ObjectTypePair.class
new file mode 100644
index 0000000..63ee576
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ObjectTypePair.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Pair.class b/bin/org/mcteam/ancientgates/gson/Pair.class
new file mode 100644
index 0000000..860badf
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Pair.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ParameterizedTypeHandlerMap.class b/bin/org/mcteam/ancientgates/gson/ParameterizedTypeHandlerMap.class
new file mode 100644
index 0000000..7edc1b1
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ParameterizedTypeHandlerMap.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/ParameterizedTypeImpl.class b/bin/org/mcteam/ancientgates/gson/ParameterizedTypeImpl.class
new file mode 100644
index 0000000..7bfb327
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/ParameterizedTypeImpl.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Preconditions.class b/bin/org/mcteam/ancientgates/gson/Preconditions.class
new file mode 100644
index 0000000..ba6266e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Preconditions.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Primitives.class b/bin/org/mcteam/ancientgates/gson/Primitives.class
new file mode 100644
index 0000000..b94d0d5
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Primitives.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/RecursiveFieldNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/RecursiveFieldNamingPolicy.class
new file mode 100644
index 0000000..ec6159c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/RecursiveFieldNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/SerializedNameAnnotationInterceptingNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/SerializedNameAnnotationInterceptingNamingPolicy.class
new file mode 100644
index 0000000..8816169
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/SerializedNameAnnotationInterceptingNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Streams$AppendableWriter$CurrentWrite.class b/bin/org/mcteam/ancientgates/gson/Streams$AppendableWriter$CurrentWrite.class
new file mode 100644
index 0000000..a89a446
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Streams$AppendableWriter$CurrentWrite.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Streams$AppendableWriter.class b/bin/org/mcteam/ancientgates/gson/Streams$AppendableWriter.class
new file mode 100644
index 0000000..ba96916
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Streams$AppendableWriter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/Streams.class b/bin/org/mcteam/ancientgates/gson/Streams.class
new file mode 100644
index 0000000..9716575
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/Streams.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/SyntheticFieldExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/SyntheticFieldExclusionStrategy.class
new file mode 100644
index 0000000..1e02a5b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/SyntheticFieldExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/TypeAdapter.class b/bin/org/mcteam/ancientgates/gson/TypeAdapter.class
new file mode 100644
index 0000000..abae9dd
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/TypeAdapter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/TypeInfo.class b/bin/org/mcteam/ancientgates/gson/TypeInfo.class
new file mode 100644
index 0000000..952cf61
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/TypeInfo.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/TypeInfoArray.class b/bin/org/mcteam/ancientgates/gson/TypeInfoArray.class
new file mode 100644
index 0000000..892e905
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/TypeInfoArray.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/TypeInfoCollection.class b/bin/org/mcteam/ancientgates/gson/TypeInfoCollection.class
new file mode 100644
index 0000000..aece322
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/TypeInfoCollection.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/TypeInfoFactory.class b/bin/org/mcteam/ancientgates/gson/TypeInfoFactory.class
new file mode 100644
index 0000000..76605f1
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/TypeInfoFactory.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/TypeInfoMap.class b/bin/org/mcteam/ancientgates/gson/TypeInfoMap.class
new file mode 100644
index 0000000..bbef67c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/TypeInfoMap.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/TypeUtils.class b/bin/org/mcteam/ancientgates/gson/TypeUtils.class
new file mode 100644
index 0000000..55672e6
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/TypeUtils.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/UpperCamelCaseSeparatorNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/UpperCamelCaseSeparatorNamingPolicy.class
new file mode 100644
index 0000000..dd1858f
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/UpperCamelCaseSeparatorNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/UpperCaseNamingPolicy.class b/bin/org/mcteam/ancientgates/gson/UpperCaseNamingPolicy.class
new file mode 100644
index 0000000..5a5215c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/UpperCaseNamingPolicy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/VersionConstants.class b/bin/org/mcteam/ancientgates/gson/VersionConstants.class
new file mode 100644
index 0000000..9f6ae54
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/VersionConstants.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/VersionExclusionStrategy.class b/bin/org/mcteam/ancientgates/gson/VersionExclusionStrategy.class
new file mode 100644
index 0000000..1b03002
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/VersionExclusionStrategy.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/annotations/Expose.class b/bin/org/mcteam/ancientgates/gson/annotations/Expose.class
new file mode 100644
index 0000000..da9fdc2
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/annotations/Expose.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/annotations/SerializedName.class b/bin/org/mcteam/ancientgates/gson/annotations/SerializedName.class
new file mode 100644
index 0000000..2f541cf
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/annotations/SerializedName.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/annotations/Since.class b/bin/org/mcteam/ancientgates/gson/annotations/Since.class
new file mode 100644
index 0000000..6adf25f
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/annotations/Since.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/annotations/Until.class b/bin/org/mcteam/ancientgates/gson/annotations/Until.class
new file mode 100644
index 0000000..cfadb8e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/annotations/Until.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/annotations/package-info.class b/bin/org/mcteam/ancientgates/gson/annotations/package-info.class
new file mode 100644
index 0000000..15bc87b
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/annotations/package-info.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/package-info.class b/bin/org/mcteam/ancientgates/gson/package-info.class
new file mode 100644
index 0000000..482cfb5
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/package-info.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/reflect/TypeToken$SimpleTypeToken.class b/bin/org/mcteam/ancientgates/gson/reflect/TypeToken$SimpleTypeToken.class
new file mode 100644
index 0000000..63a1e7a
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/reflect/TypeToken$SimpleTypeToken.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/reflect/TypeToken.class b/bin/org/mcteam/ancientgates/gson/reflect/TypeToken.class
new file mode 100644
index 0000000..d259b83
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/reflect/TypeToken.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/reflect/package-info.class b/bin/org/mcteam/ancientgates/gson/reflect/package-info.class
new file mode 100644
index 0000000..466e71c
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/reflect/package-info.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/stream/JsonReader.class b/bin/org/mcteam/ancientgates/gson/stream/JsonReader.class
new file mode 100644
index 0000000..0007a7f
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/stream/JsonReader.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/stream/JsonScope.class b/bin/org/mcteam/ancientgates/gson/stream/JsonScope.class
new file mode 100644
index 0000000..66a59e2
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/stream/JsonScope.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/stream/JsonToken.class b/bin/org/mcteam/ancientgates/gson/stream/JsonToken.class
new file mode 100644
index 0000000..89411dd
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/stream/JsonToken.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/stream/JsonWriter.class b/bin/org/mcteam/ancientgates/gson/stream/JsonWriter.class
new file mode 100644
index 0000000..f6c5a4e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/stream/JsonWriter.class differ
diff --git a/bin/org/mcteam/ancientgates/gson/stream/MalformedJsonException.class b/bin/org/mcteam/ancientgates/gson/stream/MalformedJsonException.class
new file mode 100644
index 0000000..081db47
Binary files /dev/null and b/bin/org/mcteam/ancientgates/gson/stream/MalformedJsonException.class differ
diff --git a/bin/org/mcteam/ancientgates/listeners/PluginBlockListener.class b/bin/org/mcteam/ancientgates/listeners/PluginBlockListener.class
new file mode 100644
index 0000000..f164afb
Binary files /dev/null and b/bin/org/mcteam/ancientgates/listeners/PluginBlockListener.class differ
diff --git a/bin/org/mcteam/ancientgates/listeners/PluginPlayerListener.class b/bin/org/mcteam/ancientgates/listeners/PluginPlayerListener.class
new file mode 100644
index 0000000..e7a611f
Binary files /dev/null and b/bin/org/mcteam/ancientgates/listeners/PluginPlayerListener.class differ
diff --git a/bin/org/mcteam/ancientgates/util/DiscUtil.class b/bin/org/mcteam/ancientgates/util/DiscUtil.class
new file mode 100644
index 0000000..c1a5073
Binary files /dev/null and b/bin/org/mcteam/ancientgates/util/DiscUtil.class differ
diff --git a/bin/org/mcteam/ancientgates/util/FloodUtil.class b/bin/org/mcteam/ancientgates/util/FloodUtil.class
new file mode 100644
index 0000000..3c7451e
Binary files /dev/null and b/bin/org/mcteam/ancientgates/util/FloodUtil.class differ
diff --git a/bin/org/mcteam/ancientgates/util/GeometryUtil.class b/bin/org/mcteam/ancientgates/util/GeometryUtil.class
new file mode 100644
index 0000000..6f0e929
Binary files /dev/null and b/bin/org/mcteam/ancientgates/util/GeometryUtil.class differ
diff --git a/bin/org/mcteam/ancientgates/util/TextUtil.class b/bin/org/mcteam/ancientgates/util/TextUtil.class
new file mode 100644
index 0000000..718a702
Binary files /dev/null and b/bin/org/mcteam/ancientgates/util/TextUtil.class differ
diff --git a/gson-license.txt b/gson-license.txt
new file mode 100644
index 0000000..634d1aa
--- /dev/null
+++ b/gson-license.txt
@@ -0,0 +1,13 @@
+Copyright (c) 2008-2009 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/localexport.jardesc b/localexport.jardesc
new file mode 100644
index 0000000..30829fc
--- /dev/null
+++ b/localexport.jardesc
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugin.yml b/plugin.yml
new file mode 100644
index 0000000..2226b78
--- /dev/null
+++ b/plugin.yml
@@ -0,0 +1,7 @@
+name: AncientGates
+version: 1.0.0
+main: org.mcteam.ancientgates.Plugin
+commands:
+ gate:
+ description: All of the AncientGates commands
+ usage: See documentation.
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/Conf.java b/src/org/mcteam/ancientgates/Conf.java
new file mode 100644
index 0000000..b64edc3
--- /dev/null
+++ b/src/org/mcteam/ancientgates/Conf.java
@@ -0,0 +1,75 @@
+package org.mcteam.ancientgates;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.bukkit.ChatColor;
+import org.mcteam.ancientgates.util.DiscUtil;
+
+
+public class Conf {
+ public static transient File file = new File(Plugin.instance.getDataFolder(), "conf.json");
+
+ // Colors
+ public static ChatColor colorMember = ChatColor.GREEN;
+ public static ChatColor colorAlly = ChatColor.LIGHT_PURPLE;
+ public static ChatColor colorNeutral = ChatColor.WHITE;
+ public static ChatColor colorEnemy = ChatColor.RED;
+
+ public static ChatColor colorSystem = ChatColor.YELLOW;
+ public static ChatColor colorChrome = ChatColor.GOLD;
+ public static ChatColor colorCommand = ChatColor.AQUA;
+ public static ChatColor colorParameter = ChatColor.DARK_AQUA;
+
+ private static double gateSearchRadius = 7.0;
+
+ static {
+
+ }
+
+ public static double getGateSearchRadius() {
+ return gateSearchRadius;
+ }
+
+ public static int getGateMaxArea() {
+ return (int)gateSearchRadius*10;
+ }
+
+ // -------------------------------------------- //
+ // Persistance
+ // -------------------------------------------- //
+
+ public static boolean save() {
+ //Factions.log("Saving config to disk.");
+
+ try {
+ DiscUtil.write(file, Plugin.gson.toJson(new Conf()));
+ } catch (IOException e) {
+ e.printStackTrace();
+ Plugin.log("Failed to save the config to disk.");
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean load() {
+ Plugin.log("Loading conf from disk");
+
+ if ( ! file.exists()) {
+ Plugin.log("No conf to load from disk. Creating new file.");
+ save();
+ return true;
+ }
+
+ try {
+ Plugin.gson.fromJson(DiscUtil.read(file), Conf.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Plugin.log("Failed to load the config from disk.");
+ return false;
+ }
+
+ return true;
+ }
+}
+
diff --git a/src/org/mcteam/ancientgates/Gate.java b/src/org/mcteam/ancientgates/Gate.java
new file mode 100644
index 0000000..0093390
--- /dev/null
+++ b/src/org/mcteam/ancientgates/Gate.java
@@ -0,0 +1,166 @@
+package org.mcteam.ancientgates;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.mcteam.ancientgates.gson.reflect.TypeToken;
+import org.mcteam.ancientgates.util.DiscUtil;
+import org.mcteam.ancientgates.util.FloodUtil;
+
+
+public class Gate {
+ private static transient TreeMap instances = new TreeMap(String.CASE_INSENSITIVE_ORDER);
+ private static transient File file = new File(Plugin.instance.getDataFolder(), "gates.json");
+
+ private transient String id;
+ private Location from;
+ private Location to;
+
+ public Gate() {
+
+ }
+
+ // -------------------------------------------- //
+ // Getters And Setters
+ // -------------------------------------------- //
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setFrom(Location from) {
+ this.from = from;
+ }
+
+ public Location getFrom() {
+ return from;
+ }
+
+ public void setTo(Location to) {
+ this.to = to;
+ }
+
+ public Location getTo() {
+ return to;
+ }
+
+ //----------------------------------------------//
+ // The Open And Close Methods
+ //----------------------------------------------//
+
+ public boolean open() {
+ Set blocks = FloodUtil.getGateFrameBlocks(from.getBlock());
+
+ if (blocks == null) {
+ return false;
+ }
+
+ // This is not to do an effect
+ // It is to stop portalblocks from destroyingthemself as they cant rely on non created blocks :P
+ for (Block block : blocks) {
+ block.setType(Material.GLOWSTONE);
+ }
+
+ for (Block block : blocks) {
+ block.setType(Material.PORTAL);
+ }
+
+ return true;
+ }
+
+ public void close() {
+ Set blocks = FloodUtil.getGateFrameBlocks(from.getBlock());
+
+ for (Block block : blocks) {
+ block.setType(Material.AIR);
+ }
+ }
+
+ //----------------------------------------------//
+ // Persistance and entity management
+ //----------------------------------------------//
+
+ public static Gate get(String id) {
+ return instances.get(id);
+ }
+
+ public static boolean exists(String id) {
+ return instances.containsKey(id);
+ }
+
+ public static Gate create(String id) {
+ Gate gate = new Gate();
+ gate.id = id;
+ instances.put(gate.id, gate);
+ Plugin.log("created new gate "+gate.id);
+ //faction.save();
+ return gate;
+ }
+
+ public static void delete(String id) {
+ // Remove the faction
+ instances.remove(id);
+ }
+
+ public static boolean save() {
+ try {
+ DiscUtil.write(file, Plugin.gson.toJson(instances));
+ } catch (IOException e) {
+ Plugin.log("Failed to save the gates to disk due to I/O exception.");
+ e.printStackTrace();
+ return false;
+ } catch (NullPointerException e) {
+ Plugin.log("Failed to save the gates to disk due to NPE.");
+ e.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+ public static boolean load() {
+ Plugin.log("Loading gates from disk");
+ if ( ! file.exists()) {
+ Plugin.log("No gates to load from disk. Creating new file.");
+ save();
+ return true;
+ }
+
+ try {
+ Type type = new TypeToken
+ *
+ * @author Joel Leitch
+ */
+class DelegatingJsonElementVisitor implements JsonElementVisitor {
+ private final JsonElementVisitor delegate;
+
+ protected DelegatingJsonElementVisitor(JsonElementVisitor delegate) {
+ Preconditions.checkNotNull(delegate);
+ this.delegate = delegate;
+ }
+
+ public void endArray(JsonArray array) throws IOException {
+ delegate.endArray(array);
+ }
+
+ public void endObject(JsonObject object) throws IOException {
+ delegate.endObject(object);
+ }
+
+ public void startArray(JsonArray array) throws IOException {
+ delegate.startArray(array);
+ }
+
+ public void startObject(JsonObject object) throws IOException {
+ delegate.startObject(object);
+ }
+
+ public void visitArrayMember(JsonArray parent, JsonPrimitive member,
+ boolean isFirst) throws IOException {
+ delegate.visitArrayMember(parent, member, isFirst);
+ }
+
+ public void visitArrayMember(JsonArray parent, JsonArray member,
+ boolean isFirst) throws IOException {
+ delegate.visitArrayMember(parent, member, isFirst);
+ }
+
+ public void visitArrayMember(JsonArray parent, JsonObject member,
+ boolean isFirst) throws IOException {
+ delegate.visitArrayMember(parent, member, isFirst);
+ }
+
+ public void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member,
+ boolean isFirst) throws IOException {
+ delegate.visitObjectMember(parent, memberName, member, isFirst);
+ }
+
+ public void visitObjectMember(JsonObject parent, String memberName, JsonArray member,
+ boolean isFirst) throws IOException {
+ delegate.visitObjectMember(parent, memberName, member, isFirst);
+ }
+
+ public void visitObjectMember(JsonObject parent, String memberName, JsonObject member,
+ boolean isFirst) throws IOException {
+ delegate.visitObjectMember(parent, memberName, member, isFirst);
+ }
+
+ public void visitNullObjectMember(JsonObject parent, String memberName,
+ boolean isFirst) throws IOException {
+ delegate.visitNullObjectMember(parent, memberName, isFirst);
+ }
+
+ public void visitPrimitive(JsonPrimitive primitive) throws IOException {
+ delegate.visitPrimitive(primitive);
+ }
+
+ public void visitNull() throws IOException {
+ delegate.visitNull();
+ }
+
+ public void visitNullArrayMember(JsonArray parent, boolean isFirst) throws IOException {
+ delegate.visitNullArrayMember(parent, isFirst);
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/DisjunctionExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/DisjunctionExclusionStrategy.java
new file mode 100644
index 0000000..d9bf693
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/DisjunctionExclusionStrategy.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.util.Collection;
+
+/**
+ * A wrapper class used to collect numerous {@link ExclusionStrategy} objects
+ * and perform a short-circuited OR operation.
+ *
+ * @author Joel Leitch
+ */
+final class DisjunctionExclusionStrategy implements ExclusionStrategy {
+ private final Collection strategies;
+
+ public DisjunctionExclusionStrategy(Collection strategies) {
+ Preconditions.checkNotNull(strategies);
+ this.strategies = strategies;
+ }
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ for (ExclusionStrategy strategy : strategies) {
+ if (strategy.shouldSkipField(f)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean shouldSkipClass(Class> clazz) {
+ for (ExclusionStrategy strategy : strategies) {
+ if (strategy.shouldSkipClass(clazz)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/Escaper.java b/src/org/mcteam/ancientgates/gson/Escaper.java
new file mode 100644
index 0000000..4f0d33f
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/Escaper.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A utility class that is used to perform JSON escaping so that ", <, >, etc. characters are
+ * properly encoded in the JSON string representation before returning to the client code.
+ *
+ *
This class contains a single method to escape a passed in string value:
+ *
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class Escaper {
+
+ private static final char[] HEX_CHARS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ private static final Set JS_ESCAPE_CHARS;
+ private static final Set HTML_ESCAPE_CHARS;
+
+ static {
+ Set mandatoryEscapeSet = new HashSet();
+ mandatoryEscapeSet.add('"');
+ mandatoryEscapeSet.add('\\');
+ JS_ESCAPE_CHARS = Collections.unmodifiableSet(mandatoryEscapeSet);
+
+ Set htmlEscapeSet = new HashSet();
+ htmlEscapeSet.add('<');
+ htmlEscapeSet.add('>');
+ htmlEscapeSet.add('&');
+ htmlEscapeSet.add('=');
+ htmlEscapeSet.add('\'');
+// htmlEscapeSet.add('/'); -- Removing slash for now since it causes some incompatibilities
+ HTML_ESCAPE_CHARS = Collections.unmodifiableSet(htmlEscapeSet);
+ }
+
+ private final boolean escapeHtmlCharacters;
+
+ Escaper(boolean escapeHtmlCharacters) {
+ this.escapeHtmlCharacters = escapeHtmlCharacters;
+ }
+
+ public String escapeJsonString(CharSequence plainText) {
+ StringBuffer escapedString = new StringBuffer(plainText.length() + 20);
+ try {
+ escapeJsonString(plainText, escapedString);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return escapedString.toString();
+ }
+
+ private void escapeJsonString(CharSequence plainText, StringBuffer out) throws IOException {
+ int pos = 0; // Index just past the last char in plainText written to out.
+ int len = plainText.length();
+
+ for (int charCount, i = 0; i < len; i += charCount) {
+ int codePoint = Character.codePointAt(plainText, i);
+ charCount = Character.charCount(codePoint);
+
+ if (!isControlCharacter(codePoint) && !mustEscapeCharInJsString(codePoint)) {
+ continue;
+ }
+
+ out.append(plainText, pos, i);
+ pos = i + charCount;
+ switch (codePoint) {
+ case '\b':
+ out.append("\\b");
+ break;
+ case '\t':
+ out.append("\\t");
+ break;
+ case '\n':
+ out.append("\\n");
+ break;
+ case '\f':
+ out.append("\\f");
+ break;
+ case '\r':
+ out.append("\\r");
+ break;
+ case '\\':
+ out.append("\\\\");
+ break;
+ case '/':
+ out.append("\\/");
+ break;
+ case '"':
+ out.append("\\\"");
+ break;
+ default:
+ appendHexJavaScriptRepresentation(codePoint, out);
+ break;
+ }
+ }
+ out.append(plainText, pos, len);
+ }
+
+ private boolean mustEscapeCharInJsString(int codepoint) {
+ if (!Character.isSupplementaryCodePoint(codepoint)) {
+ char c = (char) codepoint;
+ return JS_ESCAPE_CHARS.contains(c)
+ || (escapeHtmlCharacters && HTML_ESCAPE_CHARS.contains(c));
+ }
+ return false;
+ }
+
+ private static boolean isControlCharacter(int codePoint) {
+ // JSON spec defines these code points as control characters, so they must be escaped
+ return codePoint < 0x20
+ || codePoint == 0x2028 // Line separator
+ || codePoint == 0x2029 // Paragraph separator
+ || (codePoint >= 0x7f && codePoint <= 0x9f);
+ }
+
+ private static void appendHexJavaScriptRepresentation(int codePoint, Appendable out)
+ throws IOException {
+ if (Character.isSupplementaryCodePoint(codePoint)) {
+ // Handle supplementary unicode values which are not representable in
+ // javascript. We deal with these by escaping them as two 4B sequences
+ // so that they will round-trip properly when sent from java to javascript
+ // and back.
+ char[] surrogates = Character.toChars(codePoint);
+ appendHexJavaScriptRepresentation(surrogates[0], out);
+ appendHexJavaScriptRepresentation(surrogates[1], out);
+ return;
+ }
+ out.append("\\u")
+ .append(HEX_CHARS[(codePoint >>> 12) & 0xf])
+ .append(HEX_CHARS[(codePoint >>> 8) & 0xf])
+ .append(HEX_CHARS[(codePoint >>> 4) & 0xf])
+ .append(HEX_CHARS[codePoint & 0xf]);
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/ExclusionStrategy.java
new file mode 100644
index 0000000..39d9f6e
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ExclusionStrategy.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * A strategy (or policy) definition that is used to decide whether or not a field or top-level
+ * class should be serialized or deserialized as part of the JSON output/input. For serialization,
+ * if the {@link #shouldSkipClass(Class)} method returns false then that class or field type
+ * will not be part of the JSON output. For deserialization, if {@link #shouldSkipClass(Class)}
+ * returns false, then it will not be set as part of the Java object structure.
+ *
+ *
The following are a few examples that shows how you can use this exclusion mechanism.
+ *
+ *
Exclude fields and objects based on a particular class type:
+ *
Excludes fields and objects based on a particular annotation:
+ *
+ * public @interface FooAnnotation {
+ * // some implementation here
+ * }
+ *
+ * // Excludes any field (or class) that is tagged with an "@FooAnnotation"
+ * private static class FooAnnotationExclusionStrategy implements ExclusionStrategy {
+ * public boolean shouldSkipClass(Class<?> clazz) {
+ * return clazz.getAnnotation(FooAnnotation.class) != null;
+ * }
+ *
+ * public boolean shouldSkipField(FieldAttributes f) {
+ * return f.getAnnotation(FooAnnotation.class) != null;
+ * }
+ * }
+ *
+ *
+ *
Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then
+ * the {@code GsonBuilder} is required. The following is an example of how you can use the
+ * {@code GsonBuilder} to configure Gson to use one of the above sample:
+ *
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ *
+ * @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
+ *
+ * @since 1.4
+ */
+public interface ExclusionStrategy {
+
+ /**
+ * @param f the field object that is under test
+ * @return true if the field should be ignored; otherwise false
+ */
+ public boolean shouldSkipField(FieldAttributes f);
+
+ /**
+ * @param clazz the class object that is under test
+ * @return true if the class should be ignored; otherwise false
+ */
+ public boolean shouldSkipClass(Class> clazz);
+}
diff --git a/src/org/mcteam/ancientgates/gson/ExposeAnnotationDeserializationExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/ExposeAnnotationDeserializationExclusionStrategy.java
new file mode 100644
index 0000000..2cbfeb6
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ExposeAnnotationDeserializationExclusionStrategy.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mcteam.ancientgates.gson;
+
+import org.mcteam.ancientgates.gson.annotations.Expose;
+
+/**
+ * Excludes fields that do not have the {@link Expose} annotation
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy {
+
+ public boolean shouldSkipClass(Class> clazz) {
+ return false;
+ }
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ Expose annotation = f.getAnnotation(Expose.class);
+ if (annotation == null) {
+ return true;
+ }
+ return !annotation.deserialize();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ExposeAnnotationSerializationExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/ExposeAnnotationSerializationExclusionStrategy.java
new file mode 100644
index 0000000..ee366a9
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ExposeAnnotationSerializationExclusionStrategy.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import org.mcteam.ancientgates.gson.annotations.Expose;
+
+/**
+ * Excludes fields that do not have the {@link Expose} annotation
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy {
+
+ public boolean shouldSkipClass(Class> clazz) {
+ return false;
+ }
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ Expose annotation = f.getAnnotation(Expose.class);
+ if (annotation == null) {
+ return true;
+ }
+ return !annotation.serialize();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/FieldAttributes.java b/src/org/mcteam/ancientgates/gson/FieldAttributes.java
new file mode 100644
index 0000000..f7ab987
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/FieldAttributes.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * A data object that stores attributes of a field.
+ *
+ *
This class is immutable; therefore, it can be safely shared across threads.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ *
+ * @since 1.4
+ */
+public final class FieldAttributes {
+ private static final String MAX_CACHE_PROPERTY_NAME =
+ "com.bukkit.mcteam.gson.annotation_cache_size_hint";
+
+ private static final Cache, String>, Collection> ANNOTATION_CACHE =
+ new LruCache,String>, Collection>(getMaxCacheSize());
+
+ private final Class> declaringClazz;
+ private final Field field;
+ private final Class> declaredType;
+ private final boolean isSynthetic;
+ private final int modifiers;
+ private final String name;
+
+ // Fields used for lazy initialization
+ private Type genericType;
+ private Collection annotations;
+
+ /**
+ * Constructs a Field Attributes object from the {@code f}.
+ *
+ * @param f the field to pull attributes from
+ */
+ FieldAttributes(final Class> declaringClazz, final Field f) {
+ Preconditions.checkNotNull(declaringClazz);
+ this.declaringClazz = declaringClazz;
+ name = f.getName();
+ declaredType = f.getType();
+ isSynthetic = f.isSynthetic();
+ modifiers = f.getModifiers();
+ field = f;
+ }
+
+ private static int getMaxCacheSize() {
+ final int defaultMaxCacheSize = 2000;
+ try {
+ String propertyValue = System.getProperty(
+ MAX_CACHE_PROPERTY_NAME, String.valueOf(defaultMaxCacheSize));
+ return Integer.parseInt(propertyValue);
+ } catch (NumberFormatException e) {
+ return defaultMaxCacheSize;
+ }
+ }
+
+ /**
+ * @return the declaring class that contains this field
+ */
+ public Class> getDeclaringClass() {
+ return declaringClazz;
+ }
+
+ /**
+ * @return the name of the field
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ *
For example, assume the following class definition:
+ *
+ * public class Foo {
+ * private String bar;
+ * private List<String> red;
+ * }
+ *
+ * Type listParmeterizedType = new TypeToken>() {}.getType();
+ *
+ *
+ *
This method would return {@code String.class} for the {@code bar} field and
+ * {@code listParameterizedType} for the {@code red} field.
+ *
+ * @return the specific type declared for this field
+ */
+ public Type getDeclaredType() {
+ if (genericType == null) {
+ genericType = field.getGenericType();
+ }
+ return genericType;
+ }
+
+ /**
+ * Returns the {@code Class>} object that was declared for this field.
+ *
+ *
For example, assume the following class definition:
+ *
This method would return {@code String.class} for the {@code bar} field and
+ * {@code List.class} for the {@code red} field.
+ *
+ * @return the specific class object that was declared for the field
+ */
+ public Class> getDeclaredClass() {
+ return declaredType;
+ }
+
+ /**
+ * Return the {@code T} annotation object from this field if it exist; otherwise returns
+ * {@code null}.
+ *
+ * @param annotation the class of the annotation that will be retrieved
+ * @return the annotation instance if it is bound to the field; otherwise {@code null}
+ */
+ public T getAnnotation(Class annotation) {
+ return getAnnotationFromArray(getAnnotations(), annotation);
+ }
+
+ /**
+ * Return the annotations that are present on this field.
+ *
+ * @return an array of all the annotations set on the field
+ * @since 1.4
+ */
+ public Collection getAnnotations() {
+ if (annotations == null) {
+ Pair, String> key = new Pair, String>(declaringClazz, name);
+ annotations = ANNOTATION_CACHE.getElement(key);
+ if (annotations == null) {
+ annotations = Collections.unmodifiableCollection(
+ Arrays.asList(field.getAnnotations()));
+ ANNOTATION_CACHE.addElement(key, annotations);
+ }
+ }
+ return annotations;
+ }
+
+ /**
+ * Returns {@code true} if the field is defined with the {@code modifier}.
+ *
+ *
+ *
+ * @see java.lang.reflect.Modifier
+ */
+ public boolean hasModifier(int modifier) {
+ return (modifiers & modifier) != 0;
+ }
+
+ /**
+ * This is exposed internally only for the removing synthetic fields from the JSON output.
+ *
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ */
+ void set(Object instance, Object value) throws IllegalAccessException {
+ field.set(instance, value);
+ }
+
+ /**
+ * This is exposed internally only for the removing synthetic fields from the JSON output.
+ *
+ * @return true if the field is synthetic; otherwise false
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ */
+ Object get(Object instance) throws IllegalAccessException {
+ return field.get(instance);
+ }
+
+ /**
+ * This is exposed internally only for the removing synthetic fields from the JSON output.
+ *
+ * @return true if the field is synthetic; otherwise false
+ */
+ boolean isSynthetic() {
+ return isSynthetic;
+ }
+
+ /**
+ * @deprecated remove this when {@link FieldNamingStrategy} is deleted.
+ */
+ @Deprecated
+ Field getFieldObject() {
+ return field;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static T getAnnotationFromArray(
+ Collection annotations, Class annotation) {
+ for (Annotation a : annotations) {
+ if (a.annotationType() == annotation) {
+ return (T) a;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/FieldNamingPolicy.java b/src/org/mcteam/ancientgates/gson/FieldNamingPolicy.java
new file mode 100644
index 0000000..86289b4
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/FieldNamingPolicy.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * An enumeration that defines a few standard naming conventions for JSON field names.
+ * This enumeration should be used in conjunction with {@link org.mcteam.ancientgates.gson.GsonBuilder}
+ * to configure a {@link org.mcteam.ancientgates.gson.Gson} instance to properly translate Java field
+ * names into the desired JSON field names.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public enum FieldNamingPolicy {
+ /**
+ * Using this naming policy with Gson will ensure that the first "letter" of the Java
+ * field name is capitalized when serialized to its JSON form.
+ *
+ *
Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":
+ *
+ *
someFieldName ---> SomeFieldName
+ *
_someFieldName ---> _SomeFieldName
+ *
+ */
+ UPPER_CAMEL_CASE(new ModifyFirstLetterNamingPolicy(
+ ModifyFirstLetterNamingPolicy.LetterModifier.UPPER)),
+
+ /**
+ * Using this naming policy with Gson will ensure that the first "letter" of the Java
+ * field name is capitalized when serialized to its JSON form and the words will be
+ * separated by a space.
+ *
+ *
Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":
+ *
+ *
someFieldName ---> Some Field Name
+ *
_someFieldName ---> _Some Field Name
+ *
+ *
+ * @since 1.4
+ */
+ UPPER_CAMEL_CASE_WITH_SPACES(new UpperCamelCaseSeparatorNamingPolicy(" ")),
+
+ /**
+ * Using this naming policy with Gson will modify the Java Field name from its camel cased
+ * form to a lower case field name where each word is separated by an underscore (_).
+ *
+ *
Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":
+ *
+ *
someFieldName ---> some_field_name
+ *
_someFieldName ---> _some_field_name
+ *
aStringField ---> a_string_field
+ *
aURL ---> a_u_r_l
+ *
+ */
+ LOWER_CASE_WITH_UNDERSCORES(new LowerCamelCaseSeparatorNamingPolicy("_")),
+
+ /**
+ * Using this naming policy with Gson will modify the Java Field name from its camel cased
+ * form to a lower case field name where each word is separated by a dash (-).
+ *
+ *
Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":
+ *
+ *
someFieldName ---> some-field-name
+ *
_someFieldName ---> _some-field-name
+ *
aStringField ---> a-string-field
+ *
aURL ---> a-u-r-l
+ *
+ * Using dashes in JavaScript is not recommended since dash is also used for a minus sign in
+ * expressions. This requires that a field named with dashes is always accessed as a quoted
+ * property like {@code myobject['my-field']}. Accessing it as an object field
+ * {@code myobject.my-field} will result in an unintended javascript expression.
+ * @since 1.4
+ */
+ LOWER_CASE_WITH_DASHES(new LowerCamelCaseSeparatorNamingPolicy("-"));
+
+ private final FieldNamingStrategy2 namingPolicy;
+
+ private FieldNamingPolicy(FieldNamingStrategy2 namingPolicy) {
+ this.namingPolicy = namingPolicy;
+ }
+
+ FieldNamingStrategy2 getFieldNamingPolicy() {
+ return namingPolicy;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/FieldNamingStrategy.java b/src/org/mcteam/ancientgates/gson/FieldNamingStrategy.java
new file mode 100644
index 0000000..1f425dc
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/FieldNamingStrategy.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Field;
+
+/**
+ * A mechanism for providing custom field naming in Gson. This allows the client code to translate
+ * field names into a particular convention that is not supported as a normal Java field
+ * declaration rules. For example, Java does not support "-" characters in a field name.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ * @since 1.3
+ */
+public interface FieldNamingStrategy {
+
+ /**
+ * Translates the field name into its JSON field name representation.
+ *
+ * @param f the field object that we are translating
+ * @return the translated field name.
+ * @since 1.3
+ */
+ public String translateName(Field f);
+}
diff --git a/src/org/mcteam/ancientgates/gson/FieldNamingStrategy2.java b/src/org/mcteam/ancientgates/gson/FieldNamingStrategy2.java
new file mode 100644
index 0000000..ad02f35
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/FieldNamingStrategy2.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * The new mechanism for providing custom field naming in Gson. This allows the client code
+ * to translate field names into a particular convention that is not supported as a normal
+ * Java field declaration rules. For example, Java does not support "-" characters in a
+ * field name.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+interface FieldNamingStrategy2 {
+
+ /**
+ * Translates the field name into its JSON field name representation.
+ *
+ * @param f the field that is being translated
+ * @return the translated field name.
+ * @since 1.3
+ */
+ public String translateName(FieldAttributes f);
+}
diff --git a/src/org/mcteam/ancientgates/gson/FieldNamingStrategy2Adapter.java b/src/org/mcteam/ancientgates/gson/FieldNamingStrategy2Adapter.java
new file mode 100644
index 0000000..944bc2a
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/FieldNamingStrategy2Adapter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * Adapts the old "deprecated" {@link FieldNamingStrategy} to the new {@link FieldNamingStrategy2}
+ * type.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 {
+ private final FieldNamingStrategy adaptee;
+
+ public FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) {
+ Preconditions.checkNotNull(adaptee);
+ this.adaptee = adaptee;
+ }
+
+ @SuppressWarnings("deprecation")
+ public String translateName(FieldAttributes f) {
+ return adaptee.translateName(f.getFieldObject());
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/GenericArrayTypeImpl.java b/src/org/mcteam/ancientgates/gson/GenericArrayTypeImpl.java
new file mode 100644
index 0000000..c314cb5
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/GenericArrayTypeImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Type;
+
+/**
+ * An simple pojo-like immutable instance of the {@link GenericArrayType}. This object provides
+ * us the ability to create reflective types on demand. This object is required for support
+ * object similar to the one defined below:
+ *
During parsing or serialization, we know the real variable type parameter {@code T},
+ * so we can build a new {@code GenericTypeArray} with the "real" type parameters and
+ * pass that object along instead.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class GenericArrayTypeImpl implements GenericArrayType {
+
+ private final Type genericComponentType;
+
+ public GenericArrayTypeImpl(Type genericComponentType) {
+ this.genericComponentType = genericComponentType;
+ }
+
+ public Type getGenericComponentType() {
+ return genericComponentType;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof GenericArrayType)) {
+ return false;
+ }
+ GenericArrayType that = (GenericArrayType) o;
+ Type thatComponentType = that.getGenericComponentType();
+ return genericComponentType == null ?
+ thatComponentType == null : genericComponentType.equals(thatComponentType);
+ }
+
+ @Override
+ public int hashCode() {
+ return (genericComponentType == null) ? 0 : genericComponentType.hashCode();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/Gson.java b/src/org/mcteam/ancientgates/gson/Gson.java
new file mode 100644
index 0000000..0f79792
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/Gson.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.mcteam.ancientgates.gson.JsonSerializationContextDefault;
+import org.mcteam.ancientgates.gson.stream.JsonReader;
+import org.mcteam.ancientgates.gson.stream.JsonToken;
+import org.mcteam.ancientgates.gson.stream.JsonWriter;
+import org.mcteam.ancientgates.gson.stream.MalformedJsonException;
+
+/**
+ * This is the main class for using Gson. Gson is typically used by first constructing a
+ * Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)}
+ * methods on it.
+ *
+ *
You can create a Gson instance by invoking {@code new Gson()} if the default configuration
+ * is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various
+ * configuration options such as versioning support, pretty printing, custom
+ * {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.
+ *
+ *
Here is an example of how Gson is used for a simple Class:
+ *
+ *
+ * Gson gson = new Gson(); // Or use new GsonBuilder().create();
+ * MyType target = new MyType();
+ * String json = gson.toJson(target); // serializes target to Json
+ * MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
+ *
+ *
+ *
If the object that your are serializing/deserializing is a {@code ParameterizedType}
+ * (i.e. contains at least one type parameter and may be an array) then you must use the
+ * {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Here is an
+ * example for serializing and deserialing a {@code ParameterizedType}:
+ *
+ *
See the Gson User Guide
+ * for a more complete set of examples.
+ *
+ * @see org.mcteam.ancientgates.gson.reflect.TypeToken
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public final class Gson {
+
+ //TODO(inder): get rid of all the registerXXX methods and take all such parameters in the
+ // constructor instead. At the minimum, mark those methods private.
+
+ private static final String NULL_STRING = "null";
+
+ static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
+
+ // Default instances of plug-ins
+ static final AnonymousAndLocalClassExclusionStrategy DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY =
+ new AnonymousAndLocalClassExclusionStrategy();
+ static final SyntheticFieldExclusionStrategy DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY =
+ new SyntheticFieldExclusionStrategy(true);
+ static final ModifierBasedExclusionStrategy DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY =
+ new ModifierBasedExclusionStrategy(new int[] { Modifier.TRANSIENT, Modifier.STATIC });
+ static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY =
+ new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy());
+
+ private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY =
+ createExclusionStrategy(VersionConstants.IGNORE_VERSIONS);
+
+ private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
+
+ private final ExclusionStrategy serializationStrategy;
+
+ private final ExclusionStrategy deserializationStrategy;
+
+ private final FieldNamingStrategy2 fieldNamingPolicy;
+ private final MappedObjectConstructor objectConstructor;
+
+ /** Map containing Type or Class objects as keys */
+ private final ParameterizedTypeHandlerMap> serializers;
+
+ /** Map containing Type or Class objects as keys */
+ private final ParameterizedTypeHandlerMap> deserializers;
+
+ private final boolean serializeNulls;
+ private final boolean htmlSafe;
+ private final boolean generateNonExecutableJson;
+ private final boolean prettyPrinting;
+
+ /**
+ * Constructs a Gson object with default configuration. The default configuration has the
+ * following settings:
+ *
+ *
The JSON generated by toJson methods is in compact representation. This
+ * means that all the unneeded white-space is removed. You can change this behavior with
+ * {@link GsonBuilder#setPrettyPrinting()}.
+ *
The generated JSON omits all the fields that are null. Note that nulls in arrays are
+ * kept as is since an array is an ordered list. Moreover, if a field is not null, but its
+ * generated JSON is empty, the field is kept. You can configure Gson to serialize null values
+ * by setting {@link GsonBuilder#serializeNulls()}.
+ *
Gson provides default serialization and deserialization for Enums, {@link Map},
+ * {@link java.net.URL}, {@link java.net.URI}, {@link java.util.Locale}, {@link java.util.Date},
+ * {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer
+ * to change the default representation, you can do so by registering a type adapter through
+ * {@link GsonBuilder#registerTypeAdapter(Type, Object)}.
+ *
The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format
+ * ignores the millisecond portion of the date during serialization. You can change
+ * this by invoking {@link GsonBuilder#setDateFormat(int)} or
+ * {@link GsonBuilder#setDateFormat(String)}.
+ *
By default, Gson ignores the {@link org.mcteam.ancientgates.gson.annotations.Expose} annotation.
+ * You can enable Gson to serialize/deserialize only those fields marked with this annotation
+ * through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}.
+ *
By default, Gson ignores the {@link org.mcteam.ancientgates.gson.annotations.Since} annotation. You
+ * can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.
+ *
The default field naming policy for the output Json is same as in Java. So, a Java class
+ * field versionNumber will be output as "versionNumber@quot; in
+ * Json. The same rules are applied for mapping incoming Json to the Java classes. You can
+ * change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.
+ *
By default, Gson excludes transient or static fields from
+ * consideration for serialization and deserialization. You can change this behavior through
+ * {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.
+ *
+ */
+ public Gson() {
+ this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
+ new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
+ false, DefaultTypeAdapters.getDefaultSerializers(),
+ DefaultTypeAdapters.getDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false);
+ }
+
+ Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy,
+ FieldNamingStrategy2 fieldNamingPolicy, MappedObjectConstructor objectConstructor,
+ boolean serializeNulls, ParameterizedTypeHandlerMap> serializers,
+ ParameterizedTypeHandlerMap> deserializers,
+ boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) {
+ this.serializationStrategy = serializationStrategy;
+ this.deserializationStrategy = deserializationStrategy;
+ this.fieldNamingPolicy = fieldNamingPolicy;
+ this.objectConstructor = objectConstructor;
+ this.serializeNulls = serializeNulls;
+ this.serializers = serializers;
+ this.deserializers = deserializers;
+ this.generateNonExecutableJson = generateNonExecutableGson;
+ this.htmlSafe = htmlSafe;
+ this.prettyPrinting = prettyPrinting;
+ }
+
+ private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy strategy) {
+ return new ObjectNavigatorFactory(strategy, fieldNamingPolicy);
+ }
+
+ private static ExclusionStrategy createExclusionStrategy(double version) {
+ List strategies = new LinkedList();
+ strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
+ strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
+ strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
+ if (version != VersionConstants.IGNORE_VERSIONS) {
+ strategies.add(new VersionExclusionStrategy(version));
+ }
+ return new DisjunctionExclusionStrategy(strategies);
+ }
+
+ /**
+ * This method serializes the specified object into its equivalent representation as a tree of
+ * {@link JsonElement}s. This method should be used when the specified object is not a generic
+ * type. This method uses {@link Class#getClass()} to get the type for the specified object, but
+ * the {@code getClass()} loses the generic type information because of the Type Erasure feature
+ * of Java. Note that this method works fine if the any of the object fields are of generic type,
+ * just the object itself should not be of a generic type. If the object is of generic type, use
+ * {@link #toJsonTree(Object, Type)} instead.
+ *
+ * @param src the object for which Json representation is to be created setting for Gson
+ * @return Json representation of {@code src}.
+ * @since 1.4
+ */
+ public JsonElement toJsonTree(Object src) {
+ if (src == null) {
+ return JsonNull.createJsonNull();
+ }
+ return toJsonTree(src, src.getClass());
+ }
+
+ /**
+ * This method serializes the specified object, including those of generic types, into its
+ * equivalent representation as a tree of {@link JsonElement}s. This method must be used if the
+ * specified object is a generic type. For non-generic objects, use {@link #toJsonTree(Object)}
+ * instead.
+ *
+ * @param src the object for which JSON representation is to be created
+ * @param typeOfSrc The specific genericized type of src. You can obtain
+ * this type by using the {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example,
+ * to get the type for {@code Collection}, you should use:
+ *
+ * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
+ *
+ * @return Json representation of {@code src}
+ * @since 1.4
+ */
+ public JsonElement toJsonTree(Object src, Type typeOfSrc) {
+ if (src == null) {
+ return JsonNull.createJsonNull();
+ }
+ JsonSerializationContextDefault context = new JsonSerializationContextDefault(
+ createDefaultObjectNavigatorFactory(serializationStrategy), serializeNulls, serializers);
+ return context.serialize(src, typeOfSrc, true);
+ }
+
+ /**
+ * This method serializes the specified object into its equivalent Json representation.
+ * This method should be used when the specified object is not a generic type. This method uses
+ * {@link Class#getClass()} to get the type for the specified object, but the
+ * {@code getClass()} loses the generic type information because of the Type Erasure feature
+ * of Java. Note that this method works fine if the any of the object fields are of generic type,
+ * just the object itself should not be of a generic type. If the object is of generic type, use
+ * {@link #toJson(Object, Type)} instead. If you want to write out the object to a
+ * {@link Writer}, use {@link #toJson(Object, Appendable)} instead.
+ *
+ * @param src the object for which Json representation is to be created setting for Gson
+ * @return Json representation of {@code src}.
+ */
+ public String toJson(Object src) {
+ if (src == null) {
+ return serializeNulls ? NULL_STRING : "";
+ }
+ return toJson(src, src.getClass());
+ }
+
+ /**
+ * This method serializes the specified object, including those of generic types, into its
+ * equivalent Json representation. This method must be used if the specified object is a generic
+ * type. For non-generic objects, use {@link #toJson(Object)} instead. If you want to write out
+ * the object to a {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} instead.
+ *
+ * @param src the object for which JSON representation is to be created
+ * @param typeOfSrc The specific genericized type of src. You can obtain
+ * this type by using the {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example,
+ * to get the type for {@code Collection}, you should use:
+ *
+ * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
+ *
+ * @return Json representation of {@code src}
+ */
+ public String toJson(Object src, Type typeOfSrc) {
+ StringWriter writer = new StringWriter();
+ toJson(toJsonTree(src, typeOfSrc), writer);
+ return writer.toString();
+ }
+
+ /**
+ * This method serializes the specified object into its equivalent Json representation.
+ * This method should be used when the specified object is not a generic type. This method uses
+ * {@link Class#getClass()} to get the type for the specified object, but the
+ * {@code getClass()} loses the generic type information because of the Type Erasure feature
+ * of Java. Note that this method works fine if the any of the object fields are of generic type,
+ * just the object itself should not be of a generic type. If the object is of generic type, use
+ * {@link #toJson(Object, Type, Appendable)} instead.
+ *
+ * @param src the object for which Json representation is to be created setting for Gson
+ * @param writer Writer to which the Json representation needs to be written
+ * @throws JsonIOException if there was a problem writing to the writer
+ * @since 1.2
+ */
+ public void toJson(Object src, Appendable writer) throws JsonIOException {
+ try {
+ if (src != null) {
+ toJson(src, src.getClass(), writer);
+ } else if (serializeNulls) {
+ writeOutNullString(writer);
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ /**
+ * This method serializes the specified object, including those of generic types, into its
+ * equivalent Json representation. This method must be used if the specified object is a generic
+ * type. For non-generic objects, use {@link #toJson(Object, Appendable)} instead.
+ *
+ * @param src the object for which JSON representation is to be created
+ * @param typeOfSrc The specific genericized type of src. You can obtain
+ * this type by using the {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example,
+ * to get the type for {@code Collection}, you should use:
+ *
+ * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
+ *
+ * @param writer Writer to which the Json representation of src needs to be written.
+ * @throws JsonIOException if there was a problem writing to the writer
+ * @since 1.2
+ */
+ public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
+ JsonElement jsonElement = toJsonTree(src, typeOfSrc);
+ toJson(jsonElement, writer);
+ }
+
+ /**
+ * Writes the JSON representation of {@code src} of type {@code typeOfSrc} to
+ * {@code writer}.
+ * @throws JsonIOException if there was a problem writing to the writer
+ */
+ public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
+ toJson(toJsonTree(src, typeOfSrc), writer);
+ }
+
+ /**
+ * Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
+ *
+ * @param jsonElement root of a tree of {@link JsonElement}s
+ * @return JSON String representation of the tree
+ * @since 1.4
+ */
+ public String toJson(JsonElement jsonElement) {
+ StringWriter writer = new StringWriter();
+ toJson(jsonElement, writer);
+ return writer.toString();
+ }
+
+ /**
+ * Writes out the equivalent JSON for a tree of {@link JsonElement}s.
+ *
+ * @param jsonElement root of a tree of {@link JsonElement}s
+ * @param writer Writer to which the Json representation needs to be written
+ * @throws JsonIOException if there was a problem writing to the writer
+ * @since 1.4
+ */
+ public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {
+ try {
+ if (generateNonExecutableJson) {
+ writer.append(JSON_NON_EXECUTABLE_PREFIX);
+ }
+ JsonWriter jsonWriter = new JsonWriter(Streams.writerForAppendable(writer));
+ if (prettyPrinting) {
+ jsonWriter.setIndent(" ");
+ }
+ toJson(jsonElement, jsonWriter);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Writes the JSON for {@code jsonElement} to {@code writer}.
+ * @throws JsonIOException if there was a problem writing to the writer
+ */
+ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException {
+ boolean oldLenient = writer.isLenient();
+ writer.setLenient(true);
+ boolean oldHtmlSafe = writer.isHtmlSafe();
+ writer.setHtmlSafe(htmlSafe);
+ try {
+ Streams.write(jsonElement, serializeNulls, writer);
+ } catch (IOException e) {
+ throw new JsonIOException(e);
+ } finally {
+ writer.setLenient(oldLenient);
+ writer.setHtmlSafe(oldHtmlSafe);
+ }
+ }
+
+ /**
+ * This method deserializes the specified Json into an object of the specified class. It is not
+ * suitable to use if the specified class is a generic type since it will not have the generic
+ * type information because of the Type Erasure feature of Java. Therefore, this method should not
+ * be used if the desired type is a generic type. Note that this method works fine if the any of
+ * the fields of the specified object are generics, just the object itself should not be a
+ * generic type. For the cases when the object is of generic type, invoke
+ * {@link #fromJson(String, Type)}. If you have the Json in a {@link Reader} instead of
+ * a String, use {@link #fromJson(Reader, Class)} instead.
+ *
+ * @param the type of the desired object
+ * @param json the string from which the object is to be deserialized
+ * @param classOfT the class of T
+ * @return an object of type T from the string
+ * @throws JsonSyntaxException if json is not a valid representation for an object of type
+ * classOfT
+ */
+ public T fromJson(String json, Class classOfT) throws JsonSyntaxException {
+ Object object = fromJson(json, (Type) classOfT);
+ return Primitives.wrap(classOfT).cast(object);
+ }
+
+ /**
+ * This method deserializes the specified Json into an object of the specified type. This method
+ * is useful if the specified object is a generic type. For non-generic objects, use
+ * {@link #fromJson(String, Class)} instead. If you have the Json in a {@link Reader} instead of
+ * a String, use {@link #fromJson(Reader, Type)} instead.
+ *
+ * @param the type of the desired object
+ * @param json the string from which the object is to be deserialized
+ * @param typeOfT The specific genericized type of src. You can obtain this type by using the
+ * {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example, to get the type for
+ * {@code Collection}, you should use:
+ *
+ * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
+ *
+ * @return an object of type T from the string
+ * @throws JsonParseException if json is not a valid representation for an object of type typeOfT
+ * @throws JsonSyntaxException if json is not a valid representation for an object of type
+ */
+ @SuppressWarnings("unchecked")
+ public T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
+ if (json == null) {
+ return null;
+ }
+ StringReader reader = new StringReader(json);
+ T target = (T) fromJson(reader, typeOfT);
+ return target;
+ }
+
+ /**
+ * This method deserializes the Json read from the specified reader into an object of the
+ * specified class. It is not suitable to use if the specified class is a generic type since it
+ * will not have the generic type information because of the Type Erasure feature of Java.
+ * Therefore, this method should not be used if the desired type is a generic type. Note that
+ * this method works fine if the any of the fields of the specified object are generics, just the
+ * object itself should not be a generic type. For the cases when the object is of generic type,
+ * invoke {@link #fromJson(Reader, Type)}. If you have the Json in a String form instead of a
+ * {@link Reader}, use {@link #fromJson(String, Class)} instead.
+ *
+ * @param the type of the desired object
+ * @param json the reader producing the Json from which the object is to be deserialized.
+ * @param classOfT the class of T
+ * @return an object of type T from the string
+ * @throws JsonIOException if there was a problem reading from the Reader
+ * @throws JsonSyntaxException if json is not a valid representation for an object of type
+ * @since 1.2
+ */
+ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException {
+ JsonReader jsonReader = new JsonReader(json);
+ Object object = fromJson(jsonReader, classOfT);
+ assertFullConsumption(object, jsonReader);
+ return Primitives.wrap(classOfT).cast(object);
+ }
+
+ /**
+ * This method deserializes the Json read from the specified reader into an object of the
+ * specified type. This method is useful if the specified object is a generic type. For
+ * non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the Json in a
+ * String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead.
+ *
+ * @param the type of the desired object
+ * @param json the reader producing Json from which the object is to be deserialized
+ * @param typeOfT The specific genericized type of src. You can obtain this type by using the
+ * {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example, to get the type for
+ * {@code Collection}, you should use:
+ *
+ * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
+ *
+ * @return an object of type T from the json
+ * @throws JsonIOException if there was a problem reading from the Reader
+ * @throws JsonSyntaxException if json is not a valid representation for an object of type
+ * @since 1.2
+ */
+ public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
+ JsonReader jsonReader = new JsonReader(json);
+ T object = this.fromJson(jsonReader, typeOfT);
+ assertFullConsumption(object, jsonReader);
+ return object;
+ }
+
+ private static void assertFullConsumption(Object obj, JsonReader reader) {
+ try {
+ if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
+ throw new JsonIOException("JSON document was not fully consumed.");
+ }
+ } catch (MalformedJsonException e) {
+ throw new JsonSyntaxException(e);
+ } catch (IOException e) {
+ throw new JsonIOException(e);
+ }
+ }
+
+ /**
+ * Reads the next JSON value from {@code reader} and convert it to an object
+ * of type {@code typeOfT}.
+ * Since Type is not parameterized by T, this method is type unsafe and should be used carefully
+ *
+ * @throws JsonIOException if there was a problem writing to the Reader
+ * @throws JsonSyntaxException if json is not a valid representation for an object of type
+ */
+ @SuppressWarnings("unchecked")
+ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
+ boolean oldLenient = reader.isLenient();
+ reader.setLenient(true);
+ try {
+ JsonElement root = Streams.parse(reader);
+ return (T) fromJson(root, typeOfT);
+ } finally {
+ reader.setLenient(oldLenient);
+ }
+ }
+
+ /**
+ * This method deserializes the Json read from the specified parse tree into an object of the
+ * specified type. It is not suitable to use if the specified class is a generic type since it
+ * will not have the generic type information because of the Type Erasure feature of Java.
+ * Therefore, this method should not be used if the desired type is a generic type. Note that
+ * this method works fine if the any of the fields of the specified object are generics, just the
+ * object itself should not be a generic type. For the cases when the object is of generic type,
+ * invoke {@link #fromJson(JsonElement, Type)}.
+ * @param the type of the desired object
+ * @param json the root of the parse tree of {@link JsonElement}s from which the object is to
+ * be deserialized
+ * @param classOfT The class of T
+ * @return an object of type T from the json
+ * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
+ * @since 1.3
+ */
+ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException {
+ Object object = fromJson(json, (Type) classOfT);
+ return Primitives.wrap(classOfT).cast(object);
+ }
+
+ /**
+ * This method deserializes the Json read from the specified parse tree into an object of the
+ * specified type. This method is useful if the specified object is a generic type. For
+ * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead.
+ *
+ * @param the type of the desired object
+ * @param json the root of the parse tree of {@link JsonElement}s from which the object is to
+ * be deserialized
+ * @param typeOfT The specific genericized type of src. You can obtain this type by using the
+ * {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example, to get the type for
+ * {@code Collection}, you should use:
+ *
+ * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
+ *
+ * @return an object of type T from the json
+ * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
+ * @since 1.3
+ */
+ @SuppressWarnings("unchecked")
+ public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
+ if (json == null) {
+ return null;
+ }
+ JsonDeserializationContext context = new JsonDeserializationContextDefault(
+ createDefaultObjectNavigatorFactory(deserializationStrategy), deserializers,
+ objectConstructor);
+ T target = (T) context.deserialize(json, typeOfT);
+ return target;
+ }
+
+ /**
+ * Appends the {@link #NULL_STRING} to the {@code writer} object.
+ *
+ * @param writer the object to append the null value to
+ */
+ private void writeOutNullString(Appendable writer) throws IOException {
+ writer.append(NULL_STRING);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("{")
+ .append("serializeNulls:").append(serializeNulls)
+ .append(",serializers:").append(serializers)
+ .append(",deserializers:").append(deserializers)
+
+ // using the name instanceCreator instead of ObjectConstructor since the users of Gson are
+ // more familiar with the concept of Instance Creators. Moreover, the objectConstructor is
+ // just a utility class around instance creators, and its toString() only displays them.
+ .append(",instanceCreators:").append(objectConstructor)
+ .append("}");
+ return sb.toString();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/GsonBuilder.java b/src/org/mcteam/ancientgates/gson/GsonBuilder.java
new file mode 100644
index 0000000..73bc2b5
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/GsonBuilder.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+import java.text.DateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.mcteam.ancientgates.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
+
+
+/**
+ *
Use this builder to construct a {@link Gson} instance when you need to set configuration
+ * options other than the default. For {@link Gson} with default configuration, it is simpler to
+ * use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its
+ * various configuration methods, and finally calling create.
+ *
+ *
The following is an example shows how to use the {@code GsonBuilder} to construct a Gson
+ * instance:
+ *
+ *
NOTE: the order of invocation of configuration methods does not matter.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public final class GsonBuilder {
+ private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
+ new InnerClassExclusionStrategy();
+ private static final ExposeAnnotationSerializationExclusionStrategy
+ exposeAnnotationSerializationExclusionStrategy =
+ new ExposeAnnotationSerializationExclusionStrategy();
+ private static final ExposeAnnotationDeserializationExclusionStrategy
+ exposeAnnotationDeserializationExclusionStrategy =
+ new ExposeAnnotationDeserializationExclusionStrategy();
+
+ private final Collection exclusionStrategies =
+ new HashSet();
+
+ private double ignoreVersionsAfter;
+ private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy;
+ private boolean serializeInnerClasses;
+ private boolean excludeFieldsWithoutExposeAnnotation;
+ private LongSerializationPolicy longSerializationPolicy;
+ private FieldNamingStrategy2 fieldNamingPolicy;
+ private final ParameterizedTypeHandlerMap> instanceCreators;
+ private final ParameterizedTypeHandlerMap> serializers;
+ private final ParameterizedTypeHandlerMap> deserializers;
+ private boolean serializeNulls;
+ private String datePattern;
+ private int dateStyle;
+ private int timeStyle;
+ private boolean serializeSpecialFloatingPointValues;
+ private boolean escapeHtmlChars;
+ private boolean prettyPrinting;
+ private boolean generateNonExecutableJson;
+
+ /**
+ * Creates a GsonBuilder instance that can be used to build Gson with various configuration
+ * settings. GsonBuilder follows the builder pattern, and it is typically used by first
+ * invoking various configuration methods to set desired options, and finally calling
+ * {@link #create()}.
+ */
+ public GsonBuilder() {
+ // add default exclusion strategies
+ exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
+ exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
+
+ // setup default values
+ ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
+ serializeInnerClasses = true;
+ prettyPrinting = false;
+ escapeHtmlChars = true;
+ modifierBasedExclusionStrategy = Gson.DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY;
+ excludeFieldsWithoutExposeAnnotation = false;
+ longSerializationPolicy = LongSerializationPolicy.DEFAULT;
+ fieldNamingPolicy = Gson.DEFAULT_NAMING_POLICY;
+ instanceCreators = new ParameterizedTypeHandlerMap>();
+ serializers = new ParameterizedTypeHandlerMap>();
+ deserializers = new ParameterizedTypeHandlerMap>();
+ serializeNulls = false;
+ dateStyle = DateFormat.DEFAULT;
+ timeStyle = DateFormat.DEFAULT;
+ serializeSpecialFloatingPointValues = false;
+ generateNonExecutableJson = false;
+ }
+
+ /**
+ * Configures Gson to enable versioning support.
+ *
+ * @param ignoreVersionsAfter any field or type marked with a version higher than this value
+ * are ignored during serialization or deserialization.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ public GsonBuilder setVersion(double ignoreVersionsAfter) {
+ this.ignoreVersionsAfter = ignoreVersionsAfter;
+ return this;
+ }
+
+ /**
+ * Configures Gson to excludes all class fields that have the specified modifiers. By default,
+ * Gson will exclude all fields marked transient or static. This method will override that
+ * behavior.
+ *
+ * @param modifiers the field modifiers. You must use the modifiers specified in the
+ * {@link java.lang.reflect.Modifier} class. For example,
+ * {@link java.lang.reflect.Modifier#TRANSIENT},
+ * {@link java.lang.reflect.Modifier#STATIC}.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ public GsonBuilder excludeFieldsWithModifiers(int... modifiers) {
+ modifierBasedExclusionStrategy = new ModifierBasedExclusionStrategy(modifiers);
+ return this;
+ }
+
+ /**
+ * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some
+ * special text. This prevents attacks from third-party sites through script sourcing. See
+ * Gson Issue 42
+ * for details.
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.3
+ */
+ public GsonBuilder generateNonExecutableJson() {
+ this.generateNonExecutableJson = true;
+ return this;
+ }
+
+ /**
+ * Configures Gson to exclude all fields from consideration for serialization or deserialization
+ * that do not have the {@link org.mcteam.ancientgates.gson.annotations.Expose} annotation.
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
+ excludeFieldsWithoutExposeAnnotation = true;
+ return this;
+ }
+
+ /**
+ * Configure Gson to serialize null fields. By default, Gson omits all fields that are null
+ * during serialization.
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.2
+ */
+ public GsonBuilder serializeNulls() {
+ this.serializeNulls = true;
+ return this;
+ }
+
+ /**
+ * Configures Gson to exclude inner classes during serialization.
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.3
+ */
+ public GsonBuilder disableInnerClassSerialization() {
+ serializeInnerClasses = false;
+ return this;
+ }
+
+ /**
+ * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long}
+ * objects.
+ *
+ * @param serializationPolicy the particular policy to use for serializing longs.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.3
+ */
+ public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) {
+ this.longSerializationPolicy = serializationPolicy;
+ return this;
+ }
+
+ /**
+ * Configures Gson to apply a specific naming policy to an object's field during serialization
+ * and deserialization.
+ *
+ * @param namingConvention the JSON field naming convention to use for serialization and
+ * deserialization.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {
+ return setFieldNamingStrategy(namingConvention.getFieldNamingPolicy());
+ }
+
+ /**
+ * Configures Gson to apply a specific naming policy strategy to an object's field during
+ * serialization and deserialization.
+ *
+ * @param fieldNamingStrategy the actual naming strategy to apply to the fields
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.3
+ */
+ public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
+ return setFieldNamingStrategy(new FieldNamingStrategy2Adapter(fieldNamingStrategy));
+ }
+
+ /**
+ * Configures Gson to apply a specific naming policy strategy to an object's field during
+ * serialization and deserialization.
+ *
+ * @param fieldNamingStrategy the actual naming strategy to apply to the fields
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ GsonBuilder setFieldNamingStrategy(FieldNamingStrategy2 fieldNamingStrategy) {
+ this.fieldNamingPolicy =
+ new SerializedNameAnnotationInterceptingNamingPolicy(fieldNamingStrategy);
+ return this;
+ }
+
+ /**
+ * Configures Gson to apply a set of exclusion strategies during both serialization and
+ * deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
+ * This means that if one of the {@code strategies} suggests that a field (or class) should be
+ * skipped then that field (or object) is skipped during serializaiton/deserialization.
+ *
+ * @param strategies the set of strategy object to apply during object (de)serialization.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.4
+ */
+ public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
+ for (ExclusionStrategy strategy : strategies) {
+ exclusionStrategies.add(strategy);
+ }
+ return this;
+ }
+
+ /**
+ * Configures Gson to output Json that fits in a page for pretty printing. This option only
+ * affects Json serialization.
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ public GsonBuilder setPrettyPrinting() {
+ prettyPrinting = true;
+ return this;
+ }
+
+ /**
+ * By default, Gson escapes HTML characters such as < > etc. Use this option to configure
+ * Gson to pass-through HTML characters as is.
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.3
+ */
+ public GsonBuilder disableHtmlEscaping() {
+ this.escapeHtmlChars = false;
+ return this;
+ }
+
+ /**
+ * Configures Gson to serialize {@code Date} objects according to the pattern provided. You can
+ * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
+ * will be used to decide the serialization format.
+ *
+ *
Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
+ * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
+ * valid date and time patterns.
+ *
+ * @param pattern the pattern that dates will be serialized/deserialized to/from
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.2
+ */
+ public GsonBuilder setDateFormat(String pattern) {
+ // TODO(Joel): Make this fail fast if it is an invalid date format
+ this.datePattern = pattern;
+ return this;
+ }
+
+ /**
+ * Configures Gson to to serialize {@code Date} objects according to the style value provided.
+ * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
+ * invocation will be used to decide the serialization format.
+ *
+ *
Note that this style value should be one of the predefined constants in the
+ * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
+ * information on the valid style constants.
+ *
+ * @param style the predefined date style that date objects will be serialized/deserialized
+ * to/from
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.2
+ */
+ public GsonBuilder setDateFormat(int style) {
+ this.dateStyle = style;
+ this.datePattern = null;
+ return this;
+ }
+
+ /**
+ * Configures Gson to to serialize {@code Date} objects according to the style value provided.
+ * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
+ * invocation will be used to decide the serialization format.
+ *
+ *
Note that this style value should be one of the predefined constants in the
+ * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
+ * information on the valid style constants.
+ *
+ * @param dateStyle the predefined date style that date objects will be serialized/deserialized
+ * to/from
+ * @param timeStyle the predefined style for the time portion of the date objects
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.2
+ */
+ public GsonBuilder setDateFormat(int dateStyle, int timeStyle) {
+ this.dateStyle = dateStyle;
+ this.timeStyle = timeStyle;
+ this.datePattern = null;
+ return this;
+ }
+
+ /**
+ * Configures Gson for custom serialization or deserialization. This method combines the
+ * registration of an {@link InstanceCreator}, {@link JsonSerializer}, and a
+ * {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
+ * all the required interfaces for custom serialization with Gson. If an instance creator,
+ * serializer or deserializer was previously registered for the specified {@code type}, it is
+ * overwritten.
+ *
+ * @param type the type definition for the type adapter being registered
+ * @param typeAdapter This object must implement at least one of the {@link InstanceCreator},
+ * {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
+ Preconditions.checkArgument(typeAdapter instanceof JsonSerializer>
+ || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof InstanceCreator>);
+ if (typeAdapter instanceof InstanceCreator>) {
+ registerInstanceCreator(type, (InstanceCreator>) typeAdapter);
+ }
+ if (typeAdapter instanceof JsonSerializer>) {
+ registerSerializer(type, (JsonSerializer>) typeAdapter);
+ }
+ if (typeAdapter instanceof JsonDeserializer>) {
+ registerDeserializer(type, (JsonDeserializer>) typeAdapter);
+ }
+ return this;
+ }
+
+ /**
+ * Configures Gson to use a custom {@link InstanceCreator} for the specified type. If an instance
+ * creator was previously registered for the specified class, it is overwritten. Since this method
+ * takes a type instead of a Class object, it can be used to register a specific handler for a
+ * generic type corresponding to a raw type.
+ *
+ * @param the type for which instance creator is being registered
+ * @param typeOfT The Type definition for T
+ * @param instanceCreator the instance creator for T
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ private GsonBuilder registerInstanceCreator(Type typeOfT,
+ InstanceCreator extends T> instanceCreator) {
+ instanceCreators.register(typeOfT, instanceCreator);
+ return this;
+ }
+
+ /**
+ * Configures Gson to use a custom JSON serializer for the specified type. You should use this
+ * method if you want to register different serializers for different generic types corresponding
+ * to a raw type.
+ *
+ * @param the type for which the serializer is being registered
+ * @param typeOfT The type definition for T
+ * @param serializer the custom serializer
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ private GsonBuilder registerSerializer(Type typeOfT, final JsonSerializer serializer) {
+ serializers.register(typeOfT, serializer);
+ return this;
+ }
+
+ /**
+ * Configures Gson to use a custom JSON deserializer for the specified type. You should use this
+ * method if you want to register different deserializers for different generic types
+ * corresponding to a raw type.
+ *
+ * @param the type for which the deserializer is being registered
+ * @param typeOfT The type definition for T
+ * @param deserializer the custom deserializer
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ */
+ private GsonBuilder registerDeserializer(Type typeOfT, JsonDeserializer deserializer) {
+ deserializers.register(typeOfT, new JsonDeserializerExceptionWrapper(deserializer));
+ return this;
+ }
+
+ /**
+ * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
+ * This method combines the registration of an {@link InstanceCreator}, {@link JsonSerializer},
+ * and a {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter}
+ * implements all the required interfaces for custom serialization with Gson.
+ * If an instance creator, serializer or deserializer was previously registered for the specified
+ * type hierarchy, it is overwritten. If an instance creator, serializer or deserializer is
+ * registered for a specific type in the type hierarchy, it will be invoked instead of the one
+ * registered for the type hierarchy.
+ *
+ * @param baseType the class definition for the type adapter being registered for the base class
+ * or interface
+ * @param typeAdapter This object must implement at least one of the {@link InstanceCreator},
+ * {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.7
+ */
+ GsonBuilder registerTypeHierarchyAdapter(Class> baseType, Object typeAdapter) {
+ Preconditions.checkArgument(typeAdapter instanceof JsonSerializer>
+ || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof InstanceCreator>);
+ if (typeAdapter instanceof InstanceCreator>) {
+ registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator>) typeAdapter);
+ }
+ if (typeAdapter instanceof JsonSerializer>) {
+ registerSerializerForTypeHierarchy(baseType, (JsonSerializer>) typeAdapter);
+ }
+ if (typeAdapter instanceof JsonDeserializer>) {
+ registerDeserializerForTypeHierarchy(baseType, (JsonDeserializer>) typeAdapter);
+ }
+ return this;
+ }
+
+ private GsonBuilder registerInstanceCreatorForTypeHierarchy(Class> classOfT,
+ InstanceCreator extends T> instanceCreator) {
+ instanceCreators.registerForTypeHierarchy(classOfT, instanceCreator);
+ return this;
+ }
+
+ private GsonBuilder registerSerializerForTypeHierarchy(Class> classOfT,
+ final JsonSerializer serializer) {
+ serializers.registerForTypeHierarchy(classOfT, serializer);
+ return this;
+ }
+
+ private GsonBuilder registerDeserializerForTypeHierarchy(Class> classOfT,
+ JsonDeserializer deserializer) {
+ deserializers.registerForTypeHierarchy(classOfT,
+ new JsonDeserializerExceptionWrapper(deserializer));
+ return this;
+ }
+
+ /**
+ * Section 2.4 of JSON specification disallows
+ * special double values (NaN, Infinity, -Infinity). However,
+ * Javascript
+ * specification (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
+ * values. Moreover, most JavaScript engines will accept these special values in JSON without
+ * problem. So, at a practical level, it makes sense to accept these values as valid JSON even
+ * though JSON specification disallows them.
+ *
+ *
Gson always accepts these special values during deserialization. However, it outputs
+ * strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},
+ * {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value
+ * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it
+ * will throw an {@link IllegalArgumentException}. This method provides a way to override the
+ * default behavior when you know that the JSON receiver will be able to handle these special
+ * values.
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.3
+ */
+ public GsonBuilder serializeSpecialFloatingPointValues() {
+ this.serializeSpecialFloatingPointValues = true;
+ return this;
+ }
+
+ /**
+ * Creates a {@link Gson} instance based on the current configuration. This method is free of
+ * side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.
+ *
+ * @return an instance of Gson configured with the options currently set in this builder
+ */
+ public Gson create() {
+ List serializationStrategies =
+ new LinkedList(exclusionStrategies);
+ List deserializationStrategies =
+ new LinkedList(exclusionStrategies);
+
+ serializationStrategies.add(modifierBasedExclusionStrategy);
+ deserializationStrategies.add(modifierBasedExclusionStrategy);
+
+ if (!serializeInnerClasses) {
+ serializationStrategies.add(innerClassExclusionStrategy);
+ deserializationStrategies.add(innerClassExclusionStrategy);
+ }
+ if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
+ serializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
+ deserializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
+ }
+ if (excludeFieldsWithoutExposeAnnotation) {
+ serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
+ deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
+ }
+ ExclusionStrategy serializationExclusionStrategy =
+ new DisjunctionExclusionStrategy(serializationStrategies);
+ ExclusionStrategy deserializationExclusionStrategy =
+ new DisjunctionExclusionStrategy(deserializationStrategies);
+
+ ParameterizedTypeHandlerMap> customSerializers = serializers.copyOf();
+ ParameterizedTypeHandlerMap> customDeserializers = deserializers.copyOf();
+ addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers,
+ customDeserializers);
+
+ customSerializers.registerIfAbsent(DefaultTypeAdapters.getDefaultSerializers(
+ serializeSpecialFloatingPointValues, longSerializationPolicy));
+
+ customDeserializers.registerIfAbsent(DefaultTypeAdapters.getDefaultDeserializers());
+
+ ParameterizedTypeHandlerMap> customInstanceCreators =
+ instanceCreators.copyOf();
+ customInstanceCreators.registerIfAbsent(DefaultTypeAdapters.getDefaultInstanceCreators());
+
+ customSerializers.makeUnmodifiable();
+ customDeserializers.makeUnmodifiable();
+ instanceCreators.makeUnmodifiable();
+
+ MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
+
+ Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy,
+ fieldNamingPolicy, objConstructor, serializeNulls, customSerializers,
+ customDeserializers, generateNonExecutableJson, escapeHtmlChars, prettyPrinting);
+ return gson;
+ }
+
+ private static void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
+ ParameterizedTypeHandlerMap> serializers,
+ ParameterizedTypeHandlerMap> deserializers) {
+ DefaultDateTypeAdapter dateTypeAdapter = null;
+ if (datePattern != null && !"".equals(datePattern.trim())) {
+ dateTypeAdapter = new DefaultDateTypeAdapter(datePattern);
+ } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
+ dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle);
+ }
+
+ if (dateTypeAdapter != null) {
+ if (!serializers.hasSpecificHandlerFor(Date.class)) {
+ serializers.register(Date.class, dateTypeAdapter);
+ }
+ if (!deserializers.hasSpecificHandlerFor(Date.class)) {
+ deserializers.register(Date.class, dateTypeAdapter);
+ }
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/InnerClassExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/InnerClassExclusionStrategy.java
new file mode 100644
index 0000000..dd6a904
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/InnerClassExclusionStrategy.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Strategy for excluding inner classes.
+ *
+ * @author Joel Leitch
+ */
+class InnerClassExclusionStrategy implements ExclusionStrategy {
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ return isInnerClass(f.getDeclaredClass());
+ }
+
+ public boolean shouldSkipClass(Class> clazz) {
+ return isInnerClass(clazz);
+ }
+
+ private boolean isInnerClass(Class> clazz) {
+ return clazz.isMemberClass() && !isStatic(clazz);
+ }
+
+ private boolean isStatic(Class> clazz) {
+ return (clazz.getModifiers() & Modifier.STATIC) != 0;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/InstanceCreator.java b/src/org/mcteam/ancientgates/gson/InstanceCreator.java
new file mode 100644
index 0000000..e8d2009
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/InstanceCreator.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * This interface is implemented to create instances of a class that does not define a no-args
+ * constructor. If you can modify the class, you should instead add a private, or public
+ * no-args constructor. However, that is not possible for library classes, such as JDK classes, or
+ * a third-party library that you do not have source-code of. In such cases, you should define an
+ * instance creator for the class. Implementations of this interface should be registered with
+ * {@link GsonBuilder#registerTypeAdapter(Type, Object)} method before Gson will be able to use
+ * them.
+ *
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.
+ *
+ *
+ * public class Id<T> {
+ * private final Class<T> clazz;
+ * private final long value;
+ * public Id(Class<T> clazz, long value) {
+ * this.clazz = clazz;
+ * this.value = value;
+ * }
+ * }
+ *
+ *
+ *
If Gson encounters an object of type {@code Id} during deserialization, it will throw an
+ * exception. The easiest way to solve this problem will be to add a (public or private) no-args
+ * constructor as follows:
However, let us assume that the developer does not have access to the source-code of the
+ * {@code Id} class, or does not want to define a no-args constructor for it. The developer
+ * can solve this problem by defining an {@code InstanceCreator} for {@code Id}:
+ *
+ *
+ * class IdInstanceCreator implements InstanceCreator<Id> {
+ * public Id createInstance(Type type) {
+ * return new Id(Object.class, 0L);
+ * }
+ * }
+ *
+ *
+ *
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
+ * new 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:
+ *
+ *
+ * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();
+ *
+ *
+ * @param the type of object that will be created by this implementation.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public interface InstanceCreator {
+
+ /**
+ * Gson invokes this call-back method during deserialization to create an instance of the
+ * specified type. The fields of the returned instance are overwritten with the data present
+ * in the Json. Since the prior contents of the object are destroyed and overwritten, do not
+ * return an instance that is useful elsewhere. In particular, do not return a common instance,
+ * always use {@code new} to create a new instance.
+ *
+ * @param type the parameterized T represented as a {@link Type}.
+ * @return a default object instance of type T.
+ */
+ public T createInstance(Type type);
+}
diff --git a/src/org/mcteam/ancientgates/gson/JavaFieldNamingPolicy.java b/src/org/mcteam/ancientgates/gson/JavaFieldNamingPolicy.java
new file mode 100644
index 0000000..2b22710
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JavaFieldNamingPolicy.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ * A simple implementation of the {@link FieldNamingStrategy2} interface such that it does not
+ * perform any string translation of the incoming field name.
+ *
+ *
The following is an example:
+ *
+ *
+ * class IntWrapper {
+ * public int integerField = 0;
+ * }
+ *
+ * JavaFieldNamingPolicy policy = new JavaFieldNamingPolicy();
+ * String translatedFieldName =
+ * policy.translateName(IntWrapper.class.getField("integerField"));
+ *
+ * assert("integerField".equals(translatedFieldName));
+ *
+ *
+ *
This is the default {@link FieldNamingStrategy2} used by Gson.
+ *
+ * @author Joel Leitch
+ */
+final class JavaFieldNamingPolicy extends RecursiveFieldNamingPolicy {
+
+ @Override
+ protected String translateName(String target, Type fieldType, Collection annotations) {
+ return target;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonArray.java b/src/org/mcteam/ancientgates/gson/JsonArray.java
new file mode 100644
index 0000000..425b3d5
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonArray.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A class representing an array type in Json. An array is a list of {@link JsonElement}s each of
+ * which can be of a different type. This is an ordered list, meaning that the order in which
+ * elements are added is preserved.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public final class JsonArray extends JsonElement implements Iterable {
+ private final List elements;
+
+ /**
+ * Creates an empty JsonArray.
+ */
+ public JsonArray() {
+ elements = new ArrayList();
+ }
+
+ /**
+ * Adds the specified element to self.
+ *
+ * @param element the element that needs to be added to the array.
+ */
+ public void add(JsonElement element) {
+ if (element == null) {
+ element = JsonNull.createJsonNull();
+ }
+ elements.add(element);
+ }
+
+ /**
+ * Adds all the elements of the specified array to self.
+ *
+ * @param array the array whose elements need to be added to the array.
+ */
+ public void addAll(JsonArray array) {
+ elements.addAll(array.elements);
+ }
+
+ /**
+ * Reverses the elements of the array.
+ */
+ void reverse() {
+ Collections.reverse(elements);
+ }
+
+ /**
+ * Returns the number of elements in the array.
+ *
+ * @return the number of elements in the array.
+ */
+ public int size() {
+ return elements.size();
+ }
+
+ /**
+ * Returns an iterator to navigate the elemetns of the array. Since the array is an ordered list,
+ * the iterator navigates the elements in the order they were inserted.
+ *
+ * @return an iterator to navigate the elements of the array.
+ */
+ public Iterator iterator() {
+ return elements.iterator();
+ }
+
+ /**
+ * Returns the ith element of the array.
+ *
+ * @param i the index of the element that is being sought.
+ * @return the element present at the ith index.
+ * @throws IndexOutOfBoundsException if i is negative or greater than or equal to the
+ * {@link #size()} of the array.
+ */
+ public JsonElement get(int i) {
+ return elements.get(i);
+ }
+
+ /**
+ * convenience method to get this array as a {@link Number} if it contains a single element.
+ *
+ * @return get this element as a number if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid Number.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public Number getAsNumber() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsNumber();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a {@link String} if it contains a single element.
+ *
+ * @return get this element as a String if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid String.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public String getAsString() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsString();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a double if it contains a single element.
+ *
+ * @return get this element as a double if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid double.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public double getAsDouble() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsDouble();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a {@link BigDecimal} if it contains a single element.
+ *
+ * @return get this element as a {@link BigDecimal} if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
+ * @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}.
+ * @throws IllegalStateException if the array has more than one element.
+ * @since 1.2
+ */
+ @Override
+ public BigDecimal getAsBigDecimal() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsBigDecimal();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a {@link BigInteger} if it contains a single element.
+ *
+ * @return get this element as a {@link BigInteger} if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
+ * @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}.
+ * @throws IllegalStateException if the array has more than one element.
+ * @since 1.2
+ */
+ @Override
+ public BigInteger getAsBigInteger() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsBigInteger();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a float if it contains a single element.
+ *
+ * @return get this element as a float if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid float.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public float getAsFloat() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsFloat();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a long if it contains a single element.
+ *
+ * @return get this element as a long if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid long.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public long getAsLong() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsLong();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as an integer if it contains a single element.
+ *
+ * @return get this element as an integer if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid integer.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public int getAsInt() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsInt();
+ }
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public byte getAsByte() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsByte();
+ }
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public char getAsCharacter() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsCharacter();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a primitive short if it contains a single element.
+ *
+ * @return get this element as a primitive short if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid short.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public short getAsShort() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsShort();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as a boolean if it contains a single element.
+ *
+ * @return get this element as a boolean if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid boolean.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ public boolean getAsBoolean() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsBoolean();
+ }
+ throw new IllegalStateException();
+ }
+
+ /**
+ * convenience method to get this array as an Object if it contains a single element.
+ *
+ * @return get this element as an Object if it is single element array.
+ * @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
+ * is not a valid Object.
+ * @throws IllegalStateException if the array has more than one element.
+ */
+ @Override
+ Object getAsObject() {
+ if (elements.size() == 1) {
+ return elements.get(0).getAsObject();
+ }
+ throw new IllegalStateException();
+ }
+
+ @Override
+ protected void toString(Appendable sb, Escaper escaper) throws IOException {
+ sb.append('[');
+ boolean first = true;
+ for (JsonElement element : elements) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ element.toString(sb, escaper);
+ }
+ sb.append(']');
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonArrayDeserializationVisitor.java b/src/org/mcteam/ancientgates/gson/JsonArrayDeserializationVisitor.java
new file mode 100644
index 0000000..d9c9bfa
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonArrayDeserializationVisitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+
+/**
+ * A visitor that populates fields of an object with data from its equivalent
+ * JSON representation
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class JsonArrayDeserializationVisitor extends JsonDeserializationVisitor {
+
+ JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType,
+ ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
+ ParameterizedTypeHandlerMap> deserializers,
+ JsonDeserializationContext context) {
+ super(jsonArray, arrayType, factory, objectConstructor, deserializers, context);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected T constructTarget() {
+
+ TypeInfo typeInfo = new TypeInfo(targetType);
+
+ if (!json.isJsonArray()) {
+ throw new JsonParseException("Expecting array found: " + json);
+ }
+ JsonArray jsonArray = json.getAsJsonArray();
+ if (typeInfo.isArray()) {
+ TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(targetType);
+ // We know that we are getting back an array of the required type, so
+ // this typecasting is safe.
+ return (T) objectConstructor.constructArray(arrayTypeInfo.getSecondLevelType(),
+ jsonArray.size());
+ }
+ // is a collection
+ return (T) objectConstructor.construct(typeInfo.getRawClass());
+ }
+
+ public void visitArray(Object array, Type arrayType) {
+ if (!json.isJsonArray()) {
+ throw new JsonParseException("Expecting array found: " + json);
+ }
+ JsonArray jsonArray = json.getAsJsonArray();
+ TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
+ for (int i = 0; i < jsonArray.size(); i++) {
+ JsonElement jsonChild = jsonArray.get(i);
+ Object child;
+
+ if (jsonChild == null || jsonChild.isJsonNull()) {
+ child = null;
+ } else if (jsonChild instanceof JsonObject) {
+ child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild);
+ } else if (jsonChild instanceof JsonArray) {
+ child = visitChildAsArray(arrayTypeInfo.getSecondLevelType(), jsonChild.getAsJsonArray());
+ } else if (jsonChild instanceof JsonPrimitive) {
+ child = visitChildAsObject(arrayTypeInfo.getComponentRawType(),
+ jsonChild.getAsJsonPrimitive());
+ } else {
+ throw new IllegalStateException();
+ }
+ Array.set(array, i, child);
+ }
+ }
+
+ // We should not implement any other method from Visitor interface since
+ // all other methods should be invoked on JsonObjectDeserializationVisitor
+ // instead.
+
+ public void startVisitingObject(Object node) {
+ throw new JsonParseException("Expecting array but found object: " + node);
+ }
+
+ public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
+ throw new JsonParseException("Expecting array but found array field " + f.getName() + ": "
+ + obj);
+ }
+
+ public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
+ throw new JsonParseException("Expecting array but found object field " + f.getName() + ": "
+ + obj);
+ }
+
+ public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, Object parent) {
+ throw new JsonParseException("Expecting array but found field " + f.getName() + ": "
+ + parent);
+ }
+
+ public void visitPrimitive(Object primitive) {
+ throw new JsonParseException(
+ "Type information is unavailable, and the target is not a primitive: " + json);
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonDeserializationContext.java b/src/org/mcteam/ancientgates/gson/JsonDeserializationContext.java
new file mode 100644
index 0000000..61b5aa3
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonDeserializationContext.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * Context for deserialization that is passed to a custom deserializer during invocation of its
+ * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)}
+ * method.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public interface JsonDeserializationContext {
+
+ /**
+ * Invokes default deserialization on the specified object. It should never be invoked on
+ * the element received as a parameter of the
+ * {@link JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)} method. Doing
+ * so will result in an infinite loop since Gson will in-turn call the custom deserializer again.
+
+ * @param json the parse tree.
+ * @param typeOfT type of the expected return value.
+ * @param The type of the deserialized object.
+ * @return An object of type typeOfT.
+ * @throws JsonParseException if the parse tree does not contain expected data.
+ */
+ public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;
+}
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/JsonDeserializationContextDefault.java b/src/org/mcteam/ancientgates/gson/JsonDeserializationContextDefault.java
new file mode 100644
index 0000000..8451019
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonDeserializationContextDefault.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * implementation of a deserialization context for Gson
+ *
+ * @author Inderjeet Singh
+ */
+final class JsonDeserializationContextDefault implements JsonDeserializationContext {
+
+ private final ObjectNavigatorFactory navigatorFactory;
+ private final ParameterizedTypeHandlerMap> deserializers;
+ private final MappedObjectConstructor objectConstructor;
+
+ JsonDeserializationContextDefault(ObjectNavigatorFactory navigatorFactory,
+ ParameterizedTypeHandlerMap> deserializers,
+ MappedObjectConstructor objectConstructor) {
+ this.navigatorFactory = navigatorFactory;
+ this.deserializers = deserializers;
+ this.objectConstructor = objectConstructor;
+ }
+
+ ObjectConstructor getObjectConstructor() {
+ return objectConstructor;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
+ if (json == null || json.isJsonNull()) {
+ return null;
+ } else if (json.isJsonArray()) {
+ return (T) fromJsonArray(typeOfT, json.getAsJsonArray(), this);
+ } else if (json.isJsonObject()) {
+ return (T) fromJsonObject(typeOfT, json.getAsJsonObject(), this);
+ } else if (json.isJsonPrimitive()) {
+ return (T) fromJsonPrimitive(typeOfT, json.getAsJsonPrimitive(), this);
+ } else {
+ throw new JsonParseException("Failed parsing JSON source: " + json + " to Json");
+ }
+ }
+
+ private T fromJsonArray(Type arrayType, JsonArray jsonArray,
+ JsonDeserializationContext context) throws JsonParseException {
+ JsonArrayDeserializationVisitor visitor = new JsonArrayDeserializationVisitor(
+ jsonArray, arrayType, navigatorFactory, objectConstructor, deserializers, context);
+ ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, arrayType, true));
+ on.accept(visitor);
+ return visitor.getTarget();
+ }
+
+ private T fromJsonObject(Type typeOfT, JsonObject jsonObject,
+ JsonDeserializationContext context) throws JsonParseException {
+ JsonObjectDeserializationVisitor visitor = new JsonObjectDeserializationVisitor(
+ jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
+ ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, typeOfT, true));
+ on.accept(visitor);
+ return visitor.getTarget();
+ }
+
+ @SuppressWarnings("unchecked")
+ private T fromJsonPrimitive(Type typeOfT, JsonPrimitive json,
+ JsonDeserializationContext context) throws JsonParseException {
+ JsonObjectDeserializationVisitor visitor = new JsonObjectDeserializationVisitor(
+ json, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
+ ObjectNavigator on =
+ navigatorFactory.create(new ObjectTypePair(json.getAsObject(), typeOfT, true));
+ on.accept(visitor);
+ Object target = visitor.getTarget();
+ return (T) target;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonDeserializationVisitor.java b/src/org/mcteam/ancientgates/gson/JsonDeserializationVisitor.java
new file mode 100644
index 0000000..69911db
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonDeserializationVisitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * Abstract data value container for the {@link ObjectNavigator.Visitor}
+ * implementations. This class exposes the {@link #getTarget()} method
+ * which returns the class that was visited by this object.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+abstract class JsonDeserializationVisitor implements ObjectNavigator.Visitor {
+
+ protected final ObjectNavigatorFactory factory;
+ protected final ObjectConstructor objectConstructor;
+ protected final ParameterizedTypeHandlerMap> deserializers;
+ protected T target;
+ protected final JsonElement json;
+ protected final Type targetType;
+ protected final JsonDeserializationContext context;
+ protected boolean constructed;
+
+ public JsonDeserializationVisitor(JsonElement json, Type targetType,
+ ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
+ ParameterizedTypeHandlerMap> deserializers,
+ JsonDeserializationContext context) {
+ Preconditions.checkNotNull(json);
+ this.targetType = targetType;
+ this.factory = factory;
+ this.objectConstructor = objectConstructor;
+ this.deserializers = deserializers;
+ this.json = json;
+ this.context = context;
+ this.constructed = false;
+ }
+
+ public T getTarget() {
+ if (!constructed) {
+ target = constructTarget();
+ constructed = true;
+ }
+ return target;
+ }
+
+ protected abstract T constructTarget();
+
+ public void start(ObjectTypePair node) {
+ }
+
+ public void end(ObjectTypePair node) {
+ }
+
+ @SuppressWarnings("unchecked")
+ public final boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
+ Pair, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
+ if (pair == null) {
+ return false;
+ }
+ Object value = invokeCustomDeserializer(json, pair);
+ target = (T) value;
+ constructed = true;
+ return true;
+ }
+
+ protected Object invokeCustomDeserializer(JsonElement element,
+ Pair, ObjectTypePair> pair) {
+ if (element == null || element.isJsonNull()) {
+ return null;
+ }
+ Type objType = pair.second.type;
+ return (pair.first).deserialize(element, objType, context);
+ }
+
+ final Object visitChildAsObject(Type childType, JsonElement jsonChild) {
+ JsonDeserializationVisitor> childVisitor =
+ new JsonObjectDeserializationVisitor(jsonChild, childType,
+ factory, objectConstructor, deserializers, context);
+ return visitChild(childType, childVisitor);
+ }
+
+ final Object visitChildAsArray(Type childType, JsonArray jsonChild) {
+ JsonDeserializationVisitor> childVisitor =
+ new JsonArrayDeserializationVisitor(jsonChild.getAsJsonArray(), childType,
+ factory, objectConstructor, deserializers, context);
+ return visitChild(childType, childVisitor);
+ }
+
+ private Object visitChild(Type type, JsonDeserializationVisitor> childVisitor) {
+ ObjectNavigator on = factory.create(new ObjectTypePair(null, type, false));
+ on.accept(childVisitor);
+ // the underlying object may have changed during the construction phase
+ // This happens primarily because of custom deserializers
+ return childVisitor.getTarget();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonDeserializer.java b/src/org/mcteam/ancientgates/gson/JsonDeserializer.java
new file mode 100644
index 0000000..ff3e46d
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonDeserializer.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ *
Interface representing a custom deserializer for Json. You should write a custom
+ * deserializer, if you are not happy with the default deserialization done by Gson. You will
+ * also need to register this deserializer through
+ * {@link GsonBuilder#registerTypeAdapter(Type, Object)}.
+ *
+ *
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}.
+ *
+ *
+ * public class Id<T> {
+ * private final Class<T> clazz;
+ * private final long value;
+ * public Id(Class<T> clazz, long value) {
+ * this.clazz = clazz;
+ * this.value = value;
+ * }
+ * public long getValue() {
+ * return value;
+ * }
+ * }
+ *
+ *
+ *
The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the
+ * Json string to be {"clazz":com.foo.MyObject,"value":20}. Suppose, you already know
+ * the type of the field that the {@code Id} will be deserialized into, and hence just want to
+ * deserialize it from a Json string {@code 20}. You can achieve that by writing a custom
+ * deserializer:
+ *
+ *
+ * class IdDeserializer implements JsonDeserializer<Id>() {
+ * public Id fromJson(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ * throws JsonParseException {
+ * return (Id) new Id((Class)typeOfT, id.getValue());
+ * }
+ *
+ *
+ *
You will also need to register {@code IdDeserializer} with Gson as follows:
+ *
+ *
+ * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdDeserializer()).create();
+ *
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ *
+ * @param type for which the deserializer is being registered. It is possible that a
+ * deserializer may be asked to deserialize a specific generic type of the T.
+ */
+public interface JsonDeserializer {
+
+ /**
+ * Gson invokes this call-back method during deserialization when it encounters a field of the
+ * specified type.
+ *
In the implementation of this call-back method, you should consider invoking
+ * {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects
+ * for any non-trivial field of the returned object. However, you should never invoke it on the
+ * the same type passing {@code json} since that will cause an infinite loop (Gson will call your
+ * call-back method again).
+ *
+ * @param json The Json data being deserialized
+ * @param typeOfT The type of the Object to deserialize to
+ * @return a deserialized object of the specified type typeOfT which is a subclass of {@code T}
+ * @throws JsonParseException if json is not in the expected format of {@code typeofT}
+ */
+ public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException;
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonDeserializerExceptionWrapper.java b/src/org/mcteam/ancientgates/gson/JsonDeserializerExceptionWrapper.java
new file mode 100644
index 0000000..266949a
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonDeserializerExceptionWrapper.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * Decorators a {@code JsonDeserializer} instance with exception handling. This wrapper class
+ * ensures that a {@code JsonDeserializer} will not propagate any exception other than a
+ * {@link JsonParseException}.
+ *
+ * @param type of the deserializer being wrapped.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+class JsonDeserializerExceptionWrapper implements JsonDeserializer {
+
+ private final JsonDeserializer delegate;
+
+ /**
+ * Returns a wrapped {@link JsonDeserializer} object that has been decorated with
+ * {@link JsonParseException} handling.
+ *
+ * @param delegate the {@code JsonDeserializer} instance to be wrapped.
+ * @throws IllegalArgumentException if {@code delegate} is {@code null}.
+ */
+ JsonDeserializerExceptionWrapper(JsonDeserializer delegate) {
+ Preconditions.checkNotNull(delegate);
+ this.delegate = delegate;
+ }
+
+ public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ try {
+ return delegate.deserialize(json, typeOfT, context);
+ } catch (JsonParseException e) {
+ // just rethrow the exception
+ throw e;
+ } catch (Exception e) {
+ // rethrow as a JsonParseException
+ StringBuilder errorMsg = new StringBuilder()
+ .append("The JsonDeserializer ")
+ .append(delegate)
+ .append(" failed to deserialized json object ")
+ .append(json)
+ .append(" given the type ")
+ .append(typeOfT);
+ throw new JsonParseException(errorMsg.toString(), e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/JsonElement.java b/src/org/mcteam/ancientgates/gson/JsonElement.java
new file mode 100644
index 0000000..387af9a
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonElement.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * A class representing an element of Json. It could either be a {@link JsonObject}, a
+ * {@link JsonArray}, a {@link JsonPrimitive} or a {@link JsonNull}.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public abstract class JsonElement {
+ private static final Escaper BASIC_ESCAPER = new Escaper(false);
+
+ /**
+ * provides check for verifying if this element is an array or not.
+ *
+ * @return true if this element is of type {@link JsonArray}, false otherwise.
+ */
+ public boolean isJsonArray() {
+ return this instanceof JsonArray;
+ }
+
+ /**
+ * provides check for verifying if this element is a Json object or not.
+ *
+ * @return true if this element is of type {@link JsonObject}, false otherwise.
+ */
+ public boolean isJsonObject() {
+ return this instanceof JsonObject;
+ }
+
+ /**
+ * provides check for verifying if this element is a primitive or not.
+ *
+ * @return true if this element is of type {@link JsonPrimitive}, false otherwise.
+ */
+ public boolean isJsonPrimitive() {
+ return this instanceof JsonPrimitive;
+ }
+
+ /**
+ * provides check for verifying if this element represents a null value or not.
+ *
+ * @return true if this element is of type {@link JsonNull}, false otherwise.
+ * @since 1.2
+ */
+ public boolean isJsonNull() {
+ return this instanceof JsonNull;
+ }
+
+ /**
+ * convenience method to get this element as a {@link JsonObject}. If the element is of some
+ * other type, a {@link ClassCastException} will result. Hence it is best to use this method
+ * after ensuring that this element is of the desired type by calling {@link #isJsonObject()}
+ * first.
+ *
+ * @return get this element as a {@link JsonObject}.
+ * @throws IllegalStateException if the element is of another type.
+ */
+ public JsonObject getAsJsonObject() {
+ if (isJsonObject()) {
+ return (JsonObject) this;
+ }
+ throw new IllegalStateException("This is not a JSON Object.");
+ }
+
+ /**
+ * convenience method to get this element as a {@link JsonArray}. If the element is of some
+ * other type, a {@link ClassCastException} will result. Hence it is best to use this method
+ * after ensuring that this element is of the desired type by calling {@link #isJsonArray()}
+ * first.
+ *
+ * @return get this element as a {@link JsonArray}.
+ * @throws IllegalStateException if the element is of another type.
+ */
+ public JsonArray getAsJsonArray() {
+ if (isJsonArray()) {
+ return (JsonArray) this;
+ }
+ throw new IllegalStateException("This is not a JSON Array.");
+ }
+
+ /**
+ * convenience method to get this element as a {@link JsonPrimitive}. If the element is of some
+ * other type, a {@link ClassCastException} will result. Hence it is best to use this method
+ * after ensuring that this element is of the desired type by calling {@link #isJsonPrimitive()}
+ * first.
+ *
+ * @return get this element as a {@link JsonPrimitive}.
+ * @throws IllegalStateException if the element is of another type.
+ */
+ public JsonPrimitive getAsJsonPrimitive() {
+ if (isJsonPrimitive()) {
+ return (JsonPrimitive) this;
+ }
+ throw new IllegalStateException("This is not a JSON Primitive.");
+ }
+
+ /**
+ * convenience method to get this element as a {@link JsonNull}. If the element is of some
+ * other type, a {@link ClassCastException} will result. Hence it is best to use this method
+ * after ensuring that this element is of the desired type by calling {@link #isJsonNull()}
+ * first.
+ *
+ * @return get this element as a {@link JsonNull}.
+ * @throws IllegalStateException if the element is of another type.
+ * @since 1.2
+ */
+ public JsonNull getAsJsonNull() {
+ if (isJsonNull()) {
+ return (JsonNull) this;
+ }
+ throw new IllegalStateException("This is not a JSON Null.");
+ }
+
+ /**
+ * convenience method to get this element as a boolean value.
+ *
+ * @return get this element as a primitive boolean value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * boolean value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public boolean getAsBoolean() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a {@link Boolean} value.
+ *
+ * @return get this element as a {@link Boolean} value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * boolean value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ Boolean getAsBooleanWrapper() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a {@link Number}.
+ *
+ * @return get this element as a {@link Number}.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * number.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public Number getAsNumber() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a string value.
+ *
+ * @return get this element as a string value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * string value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public String getAsString() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a primitive double value.
+ *
+ * @return get this element as a primitive double value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * double value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public double getAsDouble() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a primitive float value.
+ *
+ * @return get this element as a primitive float value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * float value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public float getAsFloat() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a primitive long value.
+ *
+ * @return get this element as a primitive long value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * long value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public long getAsLong() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a primitive integer value.
+ *
+ * @return get this element as a primitive integer value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * integer value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public int getAsInt() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a primitive byte value.
+ *
+ * @return get this element as a primitive byte value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * byte value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ * @since 1.3
+ */
+ public byte getAsByte() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a primitive character value.
+ *
+ * @return get this element as a primitive char value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * char value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ * @since 1.3
+ */
+ public char getAsCharacter() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a {@link BigDecimal}.
+ *
+ * @return get this element as a {@link BigDecimal}.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive}.
+ * * @throws NumberFormatException if the element is not a valid {@link BigDecimal}.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ * @since 1.2
+ */
+ public BigDecimal getAsBigDecimal() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a {@link BigInteger}.
+ *
+ * @return get this element as a {@link BigInteger}.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive}.
+ * @throws NumberFormatException if the element is not a valid {@link BigInteger}.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ * @since 1.2
+ */
+ public BigInteger getAsBigInteger() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as a primitive short value.
+ *
+ * @return get this element as a primitive short value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * short value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ public short getAsShort() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * convenience method to get this element as an {@link Object} value.
+ *
+ * @return get this element as an Object value.
+ * @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
+ * Object value.
+ * @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
+ * more than a single element.
+ */
+ Object getAsObject() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns a String representation of this element.
+ *
+ * @return String the string representation of this element.
+ */
+ @Override
+ public String toString() {
+ try {
+ StringBuilder sb = new StringBuilder();
+ toString(sb, BASIC_ESCAPER);
+ return sb.toString();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected abstract void toString(Appendable sb, Escaper escaper) throws IOException;
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonElementVisitor.java b/src/org/mcteam/ancientgates/gson/JsonElementVisitor.java
new file mode 100644
index 0000000..fff4780
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonElementVisitor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+
+/**
+ * Definition of a visitor for a JsonElement tree.
+ *
+ * @author Inderjeet Singh
+ */
+interface JsonElementVisitor {
+ void visitPrimitive(JsonPrimitive primitive) throws IOException;
+ void visitNull() throws IOException;
+
+ void startArray(JsonArray array) throws IOException;
+ void visitArrayMember(JsonArray parent, JsonPrimitive member, boolean isFirst) throws IOException;
+ void visitArrayMember(JsonArray parent, JsonArray member, boolean isFirst) throws IOException;
+ void visitArrayMember(JsonArray parent, JsonObject member, boolean isFirst) throws IOException;
+ void visitNullArrayMember(JsonArray parent, boolean isFirst) throws IOException;
+ void endArray(JsonArray array) throws IOException;
+
+ void startObject(JsonObject object) throws IOException;
+ void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member,
+ boolean isFirst) throws IOException;
+ void visitObjectMember(JsonObject parent, String memberName, JsonArray member,
+ boolean isFirst) throws IOException;
+ void visitObjectMember(JsonObject parent, String memberName, JsonObject member,
+ boolean isFirst) throws IOException;
+ void visitNullObjectMember(JsonObject parent, String memberName,
+ boolean isFirst) throws IOException;
+ void endObject(JsonObject object) throws IOException;
+}
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/JsonFieldNameValidator.java b/src/org/mcteam/ancientgates/gson/JsonFieldNameValidator.java
new file mode 100644
index 0000000..9be5bc8
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonFieldNameValidator.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class can be used to check the validity of a JSON field name.
+ *
+ *
The primary use of this object is to ensure that any Java fields that use the
+ * {@link org.mcteam.ancientgates.gson.annotations.SerializedName} annotation is providing valid JSON
+ * field names. This will make the code fail-fast rather than letting the invalid
+ * field name propagate to the client and it fails to parse.
+ *
+ * @author Joel Leitch
+ */
+class JsonFieldNameValidator {
+ private static final String COMMON_PATTERN = "[a-zA-Z][a-zA-Z0-9\\ \\$_\\-]*$";
+
+ private static final Pattern JSON_FIELD_NAME_PATTERN =
+ Pattern.compile("(^" + COMMON_PATTERN + ")|(^[\\$_]" + COMMON_PATTERN + ")");
+
+
+ /**
+ * Performs validation on the JSON field name to ensure it is a valid field name.
+ *
+ * @param fieldName the name of the field to validate
+ * @return {@code fieldName} if it is a valid JSON field name
+ * @throws IllegalArgumentException if the field name is an invalid JSON field name
+ */
+ public String validate(String fieldName) {
+ Preconditions.checkNotNull(fieldName);
+ Preconditions.checkArgument(!"".equals(fieldName.trim()));
+
+ Matcher matcher = JSON_FIELD_NAME_PATTERN.matcher(fieldName);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(fieldName + " is not a valid JSON field name.");
+ }
+ return fieldName;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonIOException.java b/src/org/mcteam/ancientgates/gson/JsonIOException.java
new file mode 100644
index 0000000..b3d9a9d
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonIOException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mcteam.ancientgates.gson;
+
+/**
+ * This exception is raised when Gson was unable to read an input stream
+ * or write to one.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public final class JsonIOException extends JsonParseException {
+
+ private static final long serialVersionUID = 1L;
+
+ public JsonIOException(String msg) {
+ super(msg);
+ }
+
+ public JsonIOException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Creates exception with the specified cause. Consider using
+ * {@link #JsonIOException(String, Throwable)} instead if you can describe what happened.
+ *
+ * @param cause root exception that caused this exception to be thrown.
+ */
+ public JsonIOException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonNull.java b/src/org/mcteam/ancientgates/gson/JsonNull.java
new file mode 100644
index 0000000..4e69d8f
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonNull.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+
+/**
+ * A class representing a Json {@code null} value.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ * @since 1.2
+ */
+public final class JsonNull extends JsonElement {
+ private static final JsonNull INSTANCE = new JsonNull();
+
+ /**
+ * Creates a new JsonNull object.
+ */
+ public JsonNull() {
+ // Do nothing
+ }
+
+ @Override
+ protected void toString(Appendable sb, Escaper escaper) throws IOException {
+ sb.append("null");
+ }
+
+ /**
+ * All instances of JsonNull have the same hash code since they are indistinguishable
+ */
+ @Override
+ public int hashCode() {
+ return JsonNull.class.hashCode();
+ }
+
+ /**
+ * All instances of JsonNull are the same
+ */
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof JsonNull;
+ }
+
+ /**
+ * Creation method used to return an instance of a {@link JsonNull}. To reduce the memory
+ * footprint, a single object has been created for this class; therefore the same instance is
+ * being returned for each invocation of this method. This method is kept private since we
+ * prefer the users to use {@link JsonNull#JsonNull()} which is similar to how other JsonElements
+ * are created. Note that all instances of JsonNull return true for {@link #equals(Object)}
+ * when compared to each other.
+ *
+ * @return a instance of a {@link JsonNull}
+ */
+ static JsonNull createJsonNull() {
+ return INSTANCE;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonObject.java b/src/org/mcteam/ancientgates/gson/JsonObject.java
new file mode 100644
index 0000000..4d0b6db
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonObject.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class representing an object type in Json. An object consists of name-value pairs where names
+ * are strings, and values are any other type of {@link JsonElement}. This allows for a creating a
+ * tree of JsonElements. The member elements of this object are maintained in order they were added.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public final class JsonObject extends JsonElement {
+ // We are using a linked hash map because it is important to preserve
+ // the order in which elements are inserted. This is needed to ensure
+ // that the fields of an object are inserted in the order they were
+ // defined in the class.
+ private final Map members;
+
+ /**
+ * Creates an empty JsonObject.
+ */
+ public JsonObject() {
+ members = new LinkedHashMap();
+ }
+
+ /**
+ * Adds a member, which is a name-value pair, to self. The name must be a String, but the value
+ * can be an arbitrary JsonElement, thereby allowing you to build a full tree of JsonElements
+ * rooted at this node.
+ *
+ * @param property name of the member.
+ * @param value the member object.
+ */
+ public void add(String property, JsonElement value) {
+ Preconditions.checkNotNull(property);
+ if (value == null) {
+ value = JsonNull.createJsonNull();
+ }
+ members.put(property, value);
+ }
+
+ /**
+ * Removes the {@code property} from this {@link JsonObject}.
+ *
+ * @param property name of the member that should be removed.
+ * @return the {@link JsonElement} object that is being removed.
+ * @since 1.3
+ */
+ public JsonElement remove(String property) {
+ return members.remove(property);
+ }
+
+ /**
+ * Convenience method to add a primitive member. The specified value is converted to a
+ * JsonPrimitive of String.
+ *
+ * @param property name of the member.
+ * @param value the string value associated with the member.
+ */
+ public void addProperty(String property, String value) {
+ add(property, createJsonElement(value));
+ }
+
+ /**
+ * Convenience method to add a primitive member. The specified value is converted to a
+ * JsonPrimitive of Number.
+ *
+ * @param property name of the member.
+ * @param value the number value associated with the member.
+ */
+ public void addProperty(String property, Number value) {
+ add(property, createJsonElement(value));
+ }
+
+ /**
+ * Convenience method to add a boolean member. The specified value is converted to a
+ * JsonPrimitive of Boolean.
+ *
+ * @param property name of the member.
+ * @param value the number value associated with the member.
+ */
+ public void addProperty(String property, Boolean value) {
+ add(property, createJsonElement(value));
+ }
+
+ /**
+ * Convenience method to add a char member. The specified value is converted to a
+ * JsonPrimitive of Character.
+ *
+ * @param property name of the member.
+ * @param value the number value associated with the member.
+ */
+ public void addProperty(String property, Character value) {
+ add(property, createJsonElement(value));
+ }
+
+ /**
+ * Creates the proper {@link JsonElement} object from the given {@code value} object.
+ *
+ * @param value the object to generate the {@link JsonElement} for
+ * @return a {@link JsonPrimitive} if the {@code value} is not null, otherwise a {@link JsonNull}
+ */
+ private JsonElement createJsonElement(Object value) {
+ return value == null ? JsonNull.createJsonNull() : new JsonPrimitive(value);
+ }
+
+ /**
+ * Returns a set of members of this object. The set is ordered, and the order is in which the
+ * elements were added.
+ *
+ * @return a set of members of this object.
+ */
+ public Set> entrySet() {
+ return members.entrySet();
+ }
+
+ /**
+ * Convenience method to check if a member with the specified name is present in this object.
+ *
+ * @param memberName name of the member that is being checked for presence.
+ * @return true if there is a member with the specified name, false otherwise.
+ */
+ public boolean has(String memberName) {
+ return members.containsKey(memberName);
+ }
+
+ /**
+ * Returns the member with the specified name.
+ *
+ * @param memberName name of the member that is being requested.
+ * @return the member matching the name. Null if no such member exists.
+ */
+ public JsonElement get(String memberName) {
+ if (members.containsKey(memberName)) {
+ JsonElement member = members.get(memberName);
+ return member == null ? JsonNull.createJsonNull() : member;
+ }
+ return null;
+ }
+
+ /**
+ * Convenience method to get the specified member as a JsonPrimitive element.
+ *
+ * @param memberName name of the member being requested.
+ * @return the JsonPrimitive corresponding to the specified member.
+ */
+ public JsonPrimitive getAsJsonPrimitive(String memberName) {
+ return (JsonPrimitive) members.get(memberName);
+ }
+
+ /**
+ * Convenience method to get the specified member as a JsonArray.
+ *
+ * @param memberName name of the member being requested.
+ * @return the JsonArray corresponding to the specified member.
+ */
+ public JsonArray getAsJsonArray(String memberName) {
+ return (JsonArray) members.get(memberName);
+ }
+
+ /**
+ * Convenience method to get the specified member as a JsonObject.
+ *
+ * @param memberName name of the member being requested.
+ * @return the JsonObject corresponding to the specified member.
+ */
+ public JsonObject getAsJsonObject(String memberName) {
+ return (JsonObject) members.get(memberName);
+ }
+
+ @Override
+ protected void toString(Appendable sb, Escaper escaper) throws IOException {
+ sb.append('{');
+ boolean first = true;
+ for (Map.Entry entry : members.entrySet()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append('\"');
+ sb.append(escaper.escapeJsonString(entry.getKey()));
+ sb.append("\":");
+ entry.getValue().toString(sb, escaper);
+ }
+ sb.append('}');
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonObjectDeserializationVisitor.java b/src/org/mcteam/ancientgates/gson/JsonObjectDeserializationVisitor.java
new file mode 100644
index 0000000..b8439e6
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonObjectDeserializationVisitor.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * A visitor that populates fields of an object with data from its equivalent
+ * JSON representation
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class JsonObjectDeserializationVisitor extends JsonDeserializationVisitor {
+
+ JsonObjectDeserializationVisitor(JsonElement json, Type type,
+ ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
+ ParameterizedTypeHandlerMap> deserializers,
+ JsonDeserializationContext context) {
+ super(json, type, factory, objectConstructor, deserializers, context);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected T constructTarget() {
+ return (T) objectConstructor.construct(targetType);
+ }
+
+ public void startVisitingObject(Object node) {
+ // do nothing
+ }
+
+ public void visitArray(Object array, Type componentType) {
+ // should not be called since this case should invoke JsonArrayDeserializationVisitor
+ throw new JsonParseException("Expecting object but found array: " + array);
+ }
+
+ public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
+ try {
+ if (!json.isJsonObject()) {
+ throw new JsonParseException("Expecting object found: " + json);
+ }
+ JsonObject jsonObject = json.getAsJsonObject();
+ String fName = getFieldName(f);
+ JsonElement jsonChild = jsonObject.get(fName);
+ if (jsonChild != null) {
+ Object child = visitChildAsObject(typeOfF, jsonChild);
+ f.set(obj, child);
+ } else {
+ f.set(obj, null);
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
+ try {
+ if (!json.isJsonObject()) {
+ throw new JsonParseException("Expecting object found: " + json);
+ }
+ JsonObject jsonObject = json.getAsJsonObject();
+ String fName = getFieldName(f);
+ JsonArray jsonChild = (JsonArray) jsonObject.get(fName);
+ if (jsonChild != null) {
+ Object array = visitChildAsArray(typeOfF, jsonChild);
+ f.set(obj, array);
+ } else {
+ f.set(obj, null);
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String getFieldName(FieldAttributes f) {
+ FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
+ return namingPolicy.translateName(f);
+ }
+
+ public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
+ try {
+ String fName = getFieldName(f);
+ if (!json.isJsonObject()) {
+ throw new JsonParseException("Expecting object found: " + json);
+ }
+ JsonElement child = json.getAsJsonObject().get(fName);
+ TypeInfo typeInfo = new TypeInfo(declaredTypeOfField);
+ if (child == null) { // Child will be null if the field wasn't present in Json
+ return true;
+ } else if (child.isJsonNull()) {
+ if (!typeInfo.isPrimitive()) {
+ f.set(parent, null);
+ }
+ return true;
+ }
+ ObjectTypePair objTypePair = new ObjectTypePair(null, declaredTypeOfField, false);
+ Pair, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
+ if (pair == null) {
+ return false;
+ }
+ Object value = invokeCustomDeserializer(child, pair);
+ if (value != null || !typeInfo.isPrimitive()) {
+ f.set(parent, value);
+ }
+ return true;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void visitPrimitive(Object primitive) {
+ if (!json.isJsonPrimitive()) {
+ throw new JsonParseException(
+ "Type information is unavailable, and the target object is not a primitive: " + json);
+ }
+ JsonPrimitive prim = json.getAsJsonPrimitive();
+ target = (T) prim.getAsObject();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonParseException.java b/src/org/mcteam/ancientgates/gson/JsonParseException.java
new file mode 100644
index 0000000..f1eeb05
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonParseException.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * This exception is raised if there is a serious issue that occurs during parsing of a Json
+ * string. One of the main usages for this class is for the Gson infrastructure. If the incoming
+ * Json is bad/malicious, an instance of this exception is raised.
+ *
+ *
This exception is a {@link RuntimeException} because it is exposed to the client. Using a
+ * {@link RuntimeException} avoids bad coding practices on the client side where they catch the
+ * exception and do nothing. It is often the case that you want to blow up if there is a parsing
+ * error (i.e. often clients do not know how to recover from a {@link JsonParseException}.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public class JsonParseException extends RuntimeException {
+ static final long serialVersionUID = -4086729973971783390L;
+
+ /**
+ * Creates exception with the specified message. If you are wrapping another exception, consider
+ * using {@link #JsonParseException(String, Throwable)} instead.
+ *
+ * @param msg error message describing a possible cause of this exception.
+ */
+ public JsonParseException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Creates exception with the specified message and cause.
+ *
+ * @param msg error message describing what happened.
+ * @param cause root exception that caused this exception to be thrown.
+ */
+ public JsonParseException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Creates exception with the specified cause. Consider using
+ * {@link #JsonParseException(String, Throwable)} instead if you can describe what happened.
+ *
+ * @param cause root exception that caused this exception to be thrown.
+ */
+ public JsonParseException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonParser.java b/src/org/mcteam/ancientgates/gson/JsonParser.java
new file mode 100644
index 0000000..9f11c4d
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonParser.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mcteam.ancientgates.gson;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.mcteam.ancientgates.gson.stream.JsonReader;
+import org.mcteam.ancientgates.gson.stream.JsonToken;
+import org.mcteam.ancientgates.gson.stream.MalformedJsonException;
+
+/**
+ * A parser to parse Json into a parse tree of {@link JsonElement}s
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ * @since 1.3
+ */
+public final class JsonParser {
+
+ /**
+ * Parses the specified JSON string into a parse tree
+ *
+ * @param json JSON text
+ * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
+ * @throws JsonParseException if the specified text is not valid JSON
+ * @since 1.3
+ */
+ public JsonElement parse(String json) throws JsonSyntaxException {
+ return parse(new StringReader(json));
+ }
+
+ /**
+ * Parses the specified JSON string into a parse tree
+ *
+ * @param json JSON text
+ * @return a parse tree of {@link JsonElement}s corresponding to the specified JSON
+ * @throws JsonParseException if the specified text is not valid JSON
+ * @since 1.3
+ */
+ public JsonElement parse(Reader json) throws JsonIOException, JsonSyntaxException {
+ try {
+ JsonReader jsonReader = new JsonReader(json);
+ JsonElement element = parse(jsonReader);
+ if (!element.isJsonNull() && jsonReader.peek() != JsonToken.END_DOCUMENT) {
+ throw new JsonSyntaxException("Did not consume the entire document.");
+ }
+ return element;
+ } catch (MalformedJsonException e) {
+ throw new JsonSyntaxException(e);
+ } catch (IOException e) {
+ throw new JsonIOException(e);
+ } catch (NumberFormatException e) {
+ throw new JsonSyntaxException(e);
+ }
+ }
+
+ /**
+ * Returns the next value from the JSON stream as a parse tree.
+ *
+ * @throws JsonParseException if there is an IOException or if the specified
+ * text is not valid JSON
+ * @since 1.6
+ */
+ public JsonElement parse(JsonReader json) throws JsonIOException, JsonSyntaxException {
+ boolean lenient = json.isLenient();
+ json.setLenient(true);
+ try {
+ return Streams.parse(json);
+ } catch (StackOverflowError e) {
+ throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
+ } catch (OutOfMemoryError e) {
+ throw new JsonParseException("Failed parsing JSON source: " + json + " to Json", e);
+ } catch (JsonParseException e) {
+ if (e.getCause() instanceof EOFException) {
+ return JsonNull.createJsonNull();
+ }
+ throw e;
+ } finally {
+ json.setLenient(lenient);
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonPrimitive.java b/src/org/mcteam/ancientgates/gson/JsonPrimitive.java
new file mode 100644
index 0000000..2b0abfb
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonPrimitive.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * A class representing a Json primitive value. A primitive value
+ * is either a String, a Java primitive, or a Java primitive
+ * wrapper type.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public final class JsonPrimitive extends JsonElement {
+ private static final Class>[] PRIMITIVE_TYPES = { int.class, long.class, short.class,
+ float.class, double.class, byte.class, boolean.class, char.class, Integer.class, Long.class,
+ Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };
+
+ private static final BigInteger INTEGER_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
+ private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
+
+ private Object value;
+
+ /**
+ * Create a primitive containing a boolean value.
+ *
+ * @param bool the value to create the primitive with.
+ */
+ public JsonPrimitive(Boolean bool) {
+ setValue(bool);
+ }
+
+ /**
+ * Create a primitive containing a {@link Number}.
+ *
+ * @param number the value to create the primitive with.
+ */
+ public JsonPrimitive(Number number) {
+ setValue(number);
+ }
+
+ /**
+ * Create a primitive containing a String value.
+ *
+ * @param string the value to create the primitive with.
+ */
+ public JsonPrimitive(String string) {
+ setValue(string);
+ }
+
+ /**
+ * Create a primitive containing a character. The character is turned into a one character String
+ * since Json only supports String.
+ *
+ * @param c the value to create the primitive with.
+ */
+ public JsonPrimitive(Character c) {
+ setValue(c);
+ }
+
+ /**
+ * Create a primitive using the specified Object. It must be an instance of {@link Number}, a
+ * Java primitive type, or a String.
+ *
+ * @param primitive the value to create the primitive with.
+ */
+ JsonPrimitive(Object primitive) {
+ setValue(primitive);
+ }
+
+ void setValue(Object primitive) {
+ if (primitive instanceof Character) {
+ // convert characters to strings since in JSON, characters are represented as a single
+ // character string
+ char c = ((Character) primitive).charValue();
+ this.value = String.valueOf(c);
+ } else {
+ Preconditions.checkArgument(primitive instanceof Number
+ || isPrimitiveOrString(primitive));
+ this.value = primitive;
+ }
+ }
+
+ /**
+ * Check whether this primitive contains a boolean value.
+ *
+ * @return true if this primitive contains a boolean value, false otherwise.
+ */
+ public boolean isBoolean() {
+ return value instanceof Boolean;
+ }
+
+ /**
+ * convenience method to get this element as a {@link Boolean}.
+ *
+ * @return get this element as a {@link Boolean}.
+ * @throws ClassCastException if the value contained is not a valid boolean value.
+ */
+ @Override
+ Boolean getAsBooleanWrapper() {
+ return (Boolean) value;
+ }
+
+ /**
+ * convenience method to get this element as a boolean value.
+ *
+ * @return get this element as a primitive boolean value.
+ * @throws ClassCastException if the value contained is not a valid boolean value.
+ */
+ @Override
+ public boolean getAsBoolean() {
+ return isBoolean() ? getAsBooleanWrapper().booleanValue() : Boolean.parseBoolean(getAsString());
+ }
+
+ /**
+ * Check whether this primitive contains a Number.
+ *
+ * @return true if this primitive contains a Number, false otherwise.
+ */
+ public boolean isNumber() {
+ return value instanceof Number;
+ }
+
+ /**
+ * convenience method to get this element as a Number.
+ *
+ * @return get this element as a Number.
+ * @throws ClassCastException if the value contained is not a valid Number.
+ */
+ @Override
+ public Number getAsNumber() {
+ return value instanceof String ? stringToNumber((String) value) : (Number) value;
+ }
+
+ static Number stringToNumber(String value) {
+ try {
+ long longValue = Long.parseLong(value);
+ if (longValue >= Integer.MIN_VALUE && longValue <= Integer.MAX_VALUE) {
+ return (int) longValue;
+ }
+ return longValue;
+ } catch (NumberFormatException ignored) {
+ }
+
+ try {
+ return new BigDecimal(value);
+ } catch (NumberFormatException ignored) {
+ return Double.parseDouble(value); // probably NaN, -Infinity or Infinity
+ }
+ }
+
+ /**
+ * Check whether this primitive contains a String value.
+ *
+ * @return true if this primitive contains a String value, false otherwise.
+ */
+ public boolean isString() {
+ return value instanceof String;
+ }
+
+ /**
+ * convenience method to get this element as a String.
+ *
+ * @return get this element as a String.
+ * @throws ClassCastException if the value contained is not a valid String.
+ */
+ @Override
+ public String getAsString() {
+ if (isNumber()) {
+ return getAsNumber().toString();
+ } else if (isBoolean()) {
+ return getAsBooleanWrapper().toString();
+ } else {
+ return (String) value;
+ }
+ }
+
+ /**
+ * convenience method to get this element as a primitive double.
+ *
+ * @return get this element as a primitive double.
+ * @throws ClassCastException if the value contained is not a valid double.
+ */
+ @Override
+ public double getAsDouble() {
+ return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString());
+ }
+
+ /**
+ * convenience method to get this element as a {@link BigDecimal}.
+ *
+ * @return get this element as a {@link BigDecimal}.
+ * @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}.
+ */
+ @Override
+ public BigDecimal getAsBigDecimal() {
+ return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());
+ }
+
+ /**
+ * convenience method to get this element as a {@link BigInteger}.
+ *
+ * @return get this element as a {@link BigInteger}.
+ * @throws NumberFormatException if the value contained is not a valid {@link BigInteger}.
+ */
+ @Override
+ public BigInteger getAsBigInteger() {
+ return value instanceof BigInteger ? (BigInteger) value : new BigInteger(value.toString());
+ }
+
+ /**
+ * convenience method to get this element as a float.
+ *
+ * @return get this element as a float.
+ * @throws ClassCastException if the value contained is not a valid float.
+ */
+ @Override
+ public float getAsFloat() {
+ return isNumber() ? getAsNumber().floatValue() : Float.parseFloat(getAsString());
+ }
+
+ /**
+ * convenience method to get this element as a primitive long.
+ *
+ * @return get this element as a primitive long.
+ * @throws ClassCastException if the value contained is not a valid long.
+ */
+ @Override
+ public long getAsLong() {
+ return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString());
+ }
+
+ /**
+ * convenience method to get this element as a primitive short.
+ *
+ * @return get this element as a primitive short.
+ * @throws ClassCastException if the value contained is not a valid short value.
+ */
+ @Override
+ public short getAsShort() {
+ return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString());
+ }
+
+ /**
+ * convenience method to get this element as a primitive integer.
+ *
+ * @return get this element as a primitive integer.
+ * @throws ClassCastException if the value contained is not a valid integer.
+ */
+ @Override
+ public int getAsInt() {
+ return isNumber() ? getAsNumber().intValue() : Integer.parseInt(getAsString());
+ }
+
+ @Override
+ public byte getAsByte() {
+ return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString());
+ }
+
+ @Override
+ public char getAsCharacter() {
+ return getAsString().charAt(0);
+ }
+
+ /**
+ * convenience method to get this element as an Object.
+ *
+ * @return get this element as an Object that can be converted to a suitable value.
+ */
+ @Override
+ Object getAsObject() {
+ if (value instanceof BigInteger) {
+ BigInteger big = (BigInteger) value;
+ if (big.compareTo(INTEGER_MAX) < 0) {
+ return big.intValue();
+ } else if (big.compareTo(LONG_MAX) < 0) {
+ return big.longValue();
+ }
+ }
+ // No need to convert to float or double since those lose precision
+ return value;
+ }
+
+ @Override
+ protected void toString(Appendable sb, Escaper escaper) throws IOException {
+ if (isString()) {
+ sb.append('"');
+ sb.append(escaper.escapeJsonString(value.toString()));
+ sb.append('"');
+ } else {
+ sb.append(value.toString());
+ }
+ }
+
+ private static boolean isPrimitiveOrString(Object target) {
+ if (target instanceof String) {
+ return true;
+ }
+
+ Class> classOfPrimitive = target.getClass();
+ for (Class> standardPrimitive : PRIMITIVE_TYPES) {
+ if (standardPrimitive.isAssignableFrom(classOfPrimitive)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (value == null) {
+ return 31;
+ }
+ // Using recommended hashing algorithm from Effective Java for longs and doubles
+ if (isIntegral(this)) {
+ long value = getAsNumber().longValue();
+ return (int) (value ^ (value >>> 32));
+ }
+ if (isFloatingPoint(this)) {
+ long value = Double.doubleToLongBits(getAsNumber().doubleValue());
+ return (int) (value ^ (value >>> 32));
+ }
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ JsonPrimitive other = (JsonPrimitive)obj;
+ if (value == null) {
+ return other.value == null;
+ }
+ if (isIntegral(this) && isIntegral(other)) {
+ return getAsNumber().longValue() == other.getAsNumber().longValue();
+ }
+ if (isFloatingPoint(this) && isFloatingPoint(other)) {
+ return getAsNumber().doubleValue() == other.getAsNumber().doubleValue();
+ }
+ return value.equals(other.value);
+ }
+
+ /**
+ * Returns true if the specified number is an integral type
+ * (Long, Integer, Short, Byte, BigInteger)
+ */
+ private static boolean isIntegral(JsonPrimitive primitive) {
+ if (primitive.value instanceof Number) {
+ Number number = (Number) primitive.value;
+ return number instanceof BigInteger || number instanceof Long || number instanceof Integer
+ || number instanceof Short || number instanceof Byte;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the specified number is a floating point type (BigDecimal, double, float)
+ */
+ private static boolean isFloatingPoint(JsonPrimitive primitive) {
+ if (primitive.value instanceof Number) {
+ Number number = (Number) primitive.value;
+ return number instanceof BigDecimal || number instanceof Double || number instanceof Float;
+ }
+ return false;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonSerializationContext.java b/src/org/mcteam/ancientgates/gson/JsonSerializationContext.java
new file mode 100644
index 0000000..390bf27
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonSerializationContext.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * Context for serialization that is passed to a custom serializer during invocation of its
+ * {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public interface JsonSerializationContext {
+
+ /**
+ * Invokes default serialization on the specified object.
+ *
+ * @param src the object that needs to be serialized.
+ * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
+ */
+ public JsonElement serialize(Object src);
+
+ /**
+ * Invokes default serialization on the specified object passing the specific type information.
+ * It should never be invoked on the element received as a parameter of the
+ * {@link JsonSerializer#serialize(Object, Type, JsonSerializationContext)} method. Doing
+ * so will result in an infinite loop since Gson will in-turn call the custom serializer again.
+ *
+ * @param src the object that needs to be serialized.
+ * @param typeOfSrc the actual genericized type of src object.
+ * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
+ */
+ public JsonElement serialize(Object src, Type typeOfSrc);
+}
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/JsonSerializationContextDefault.java b/src/org/mcteam/ancientgates/gson/JsonSerializationContextDefault.java
new file mode 100644
index 0000000..b64abfb
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonSerializationContextDefault.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * An implementation of serialization context for Gson.
+ *
+ * @author Inderjeet Singh
+ */
+final class JsonSerializationContextDefault implements JsonSerializationContext {
+
+ private final ObjectNavigatorFactory factory;
+ private final ParameterizedTypeHandlerMap> serializers;
+ private final boolean serializeNulls;
+ private final MemoryRefStack ancestors;
+
+ JsonSerializationContextDefault(ObjectNavigatorFactory factory, boolean serializeNulls,
+ ParameterizedTypeHandlerMap> serializers) {
+ this.factory = factory;
+ this.serializeNulls = serializeNulls;
+ this.serializers = serializers;
+ this.ancestors = new MemoryRefStack();
+ }
+
+ public JsonElement serialize(Object src) {
+ if (src == null) {
+ return JsonNull.createJsonNull();
+ }
+ return serialize(src, src.getClass(), true);
+ }
+
+ public JsonElement serialize(Object src, Type typeOfSrc) {
+ return serialize(src, typeOfSrc, true);
+ }
+
+ public JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
+ ObjectNavigator on = factory.create(new ObjectTypePair(src, typeOfSrc, preserveType));
+ JsonSerializationVisitor visitor =
+ new JsonSerializationVisitor(factory, serializeNulls, serializers, this, ancestors);
+ on.accept(visitor);
+ return visitor.getJsonElement();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonSerializationVisitor.java b/src/org/mcteam/ancientgates/gson/JsonSerializationVisitor.java
new file mode 100644
index 0000000..220a3be
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonSerializationVisitor.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+
+/**
+ * A visitor that adds JSON elements corresponding to each field of an object
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
+
+ private final ObjectNavigatorFactory factory;
+ private final ParameterizedTypeHandlerMap> serializers;
+ private final boolean serializeNulls;
+ private final JsonSerializationContext context;
+ private final MemoryRefStack ancestors;
+ private JsonElement root;
+
+ JsonSerializationVisitor(ObjectNavigatorFactory factory, boolean serializeNulls,
+ ParameterizedTypeHandlerMap> serializers, JsonSerializationContext context,
+ MemoryRefStack ancestors) {
+ this.factory = factory;
+ this.serializeNulls = serializeNulls;
+ this.serializers = serializers;
+ this.context = context;
+ this.ancestors = ancestors;
+ }
+
+ public Object getTarget() {
+ return null;
+ }
+
+ public void start(ObjectTypePair node) {
+ if (node == null) {
+ return;
+ }
+ if (ancestors.contains(node)) {
+ throw new CircularReferenceException(node);
+ }
+ ancestors.push(node);
+ }
+
+ public void end(ObjectTypePair node) {
+ if (node != null) {
+ ancestors.pop();
+ }
+ }
+
+ public void startVisitingObject(Object node) {
+ assignToRoot(new JsonObject());
+ }
+
+ public void visitArray(Object array, Type arrayType) {
+ assignToRoot(new JsonArray());
+ int length = Array.getLength(array);
+ TypeInfoArray fieldTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
+ Type componentType = fieldTypeInfo.getSecondLevelType();
+ for (int i = 0; i < length; ++i) {
+ Object child = Array.get(array, i);
+ Type childType = componentType;
+ // we should not get more specific component type yet since it is possible
+ // that a custom
+ // serializer is registered for the componentType
+ addAsArrayElement(new ObjectTypePair(child, childType, false));
+ }
+ }
+
+ public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
+ try {
+ if (isFieldNull(f, obj)) {
+ if (serializeNulls) {
+ addChildAsElement(f, JsonNull.createJsonNull());
+ }
+ } else {
+ Object array = getFieldValue(f, obj);
+ addAsChildOfObject(f, new ObjectTypePair(array, typeOfF, false));
+ }
+ } catch (CircularReferenceException e) {
+ throw e.createDetailedException(f);
+ }
+ }
+
+ public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
+ try {
+ if (isFieldNull(f, obj)) {
+ if (serializeNulls) {
+ addChildAsElement(f, JsonNull.createJsonNull());
+ }
+ } else {
+ Object fieldValue = getFieldValue(f, obj);
+ // we should not get more specific component type yet since it is
+ // possible that a custom
+ // serializer is registered for the componentType
+ addAsChildOfObject(f, new ObjectTypePair(fieldValue, typeOfF, false));
+ }
+ } catch (CircularReferenceException e) {
+ throw e.createDetailedException(f);
+ }
+ }
+
+ public void visitPrimitive(Object obj) {
+ JsonElement json = obj == null ? JsonNull.createJsonNull() : new JsonPrimitive(obj);
+ assignToRoot(json);
+ }
+
+ private void addAsChildOfObject(FieldAttributes f, ObjectTypePair fieldValuePair) {
+ JsonElement childElement = getJsonElementForChild(fieldValuePair);
+ addChildAsElement(f, childElement);
+ }
+
+ private void addChildAsElement(FieldAttributes f, JsonElement childElement) {
+ FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
+ root.getAsJsonObject().add(namingPolicy.translateName(f), childElement);
+ }
+
+ private void addAsArrayElement(ObjectTypePair elementTypePair) {
+ if (elementTypePair.getObject() == null) {
+ root.getAsJsonArray().add(JsonNull.createJsonNull());
+ } else {
+ JsonElement childElement = getJsonElementForChild(elementTypePair);
+ root.getAsJsonArray().add(childElement);
+ }
+ }
+
+ private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) {
+ ObjectNavigator on = factory.create(fieldValueTypePair);
+ JsonSerializationVisitor childVisitor =
+ new JsonSerializationVisitor(factory, serializeNulls, serializers, context, ancestors);
+ on.accept(childVisitor);
+ return childVisitor.getJsonElement();
+ }
+
+ public boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
+ try {
+ Object obj = objTypePair.getObject();
+ if (obj == null) {
+ if (serializeNulls) {
+ assignToRoot(JsonNull.createJsonNull());
+ }
+ return true;
+ }
+ JsonElement element = findAndInvokeCustomSerializer(objTypePair);
+ if (element != null) {
+ assignToRoot(element);
+ return true;
+ }
+ return false;
+ } catch (CircularReferenceException e) {
+ throw e.createDetailedException(null);
+ }
+ }
+
+ /**
+ * objTypePair.getObject() must not be null
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private JsonElement findAndInvokeCustomSerializer(ObjectTypePair objTypePair) {
+ Pair,ObjectTypePair> pair = objTypePair.getMatchingHandler(serializers);
+ if (pair == null) {
+ return null;
+ }
+ JsonSerializer serializer = pair.first;
+ objTypePair = pair.second;
+ start(objTypePair);
+ try {
+ JsonElement element =
+ serializer.serialize(objTypePair.getObject(), objTypePair.getType(), context);
+ return element == null ? JsonNull.createJsonNull() : element;
+ } finally {
+ end(objTypePair);
+ }
+ }
+
+ public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
+ try {
+ Preconditions.checkState(root.isJsonObject());
+ Object obj = f.get(parent);
+ if (obj == null) {
+ if (serializeNulls) {
+ addChildAsElement(f, JsonNull.createJsonNull());
+ }
+ return true;
+ }
+ ObjectTypePair objTypePair = new ObjectTypePair(obj, declaredTypeOfField, false);
+ JsonElement child = findAndInvokeCustomSerializer(objTypePair);
+ if (child != null) {
+ addChildAsElement(f, child);
+ return true;
+ }
+ return false;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException();
+ } catch (CircularReferenceException e) {
+ throw e.createDetailedException(f);
+ }
+ }
+
+ private void assignToRoot(JsonElement newRoot) {
+ Preconditions.checkNotNull(newRoot);
+ root = newRoot;
+ }
+
+ private boolean isFieldNull(FieldAttributes f, Object obj) {
+ return getFieldValue(f, obj) == null;
+ }
+
+ private Object getFieldValue(FieldAttributes f, Object obj) {
+ try {
+ return f.get(obj);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public JsonElement getJsonElement() {
+ return root;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonSerializer.java b/src/org/mcteam/ancientgates/gson/JsonSerializer.java
new file mode 100644
index 0000000..ad06c4d
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonSerializer.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * Interface representing a custom serializer for Json. You should write a custom serializer, if
+ * you are not happy with the default serialization done by Gson. You will also need to register
+ * this serializer through {@link org.mcteam.ancientgates.gson.GsonBuilder#registerTypeAdapter(Type, Object)}.
+ *
+ *
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}.
+ *
+ *
+ * public class Id<T> {
+ * private final Class<T> clazz;
+ * private final long value;
+ *
+ * public Id(Class<T> clazz, long value) {
+ * this.clazz = clazz;
+ * this.value = value;
+ * }
+ *
+ * public long getValue() {
+ * return value;
+ * }
+ * }
+ *
+ *
+ *
The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be
+ * {"clazz":com.foo.MyObject,"value":20}. Suppose, you just want the output to be
+ * the value instead, which is {@code 20} in this case. You can achieve that by writing a custom
+ * serializer:
+ *
+ *
+ * class IdSerializer implements JsonSerializer<Id>() {
+ * public JsonElement toJson(Id id, Type typeOfId, JsonSerializationContext context) {
+ * return new JsonPrimitive(id.getValue());
+ * }
+ * }
+ *
+ *
+ *
You will also need to register {@code IdSerializer} with Gson as follows:
+ *
+ * Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).create();
+ *
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ *
+ * @param type for which the serializer is being registered. It is possible that a serializer
+ * may be asked to serialize a specific generic type of the T.
+ */
+public interface JsonSerializer {
+
+ /**
+ * Gson invokes this call-back method during serialization when it encounters a field of the
+ * specified type.
+ *
+ *
In the implementation of this call-back method, you should consider invoking
+ * {@link JsonSerializationContext#serialize(Object, Type)} method to create JsonElements for any
+ * non-trivial field of the {@code src} object. However, you should never invoke it on the
+ * {@code src} object itself since that will cause an infinite loop (Gson will call your
+ * call-back method again).
+ *
+ * @param src the object that needs to be converted to Json.
+ * @param typeOfSrc the actual type (fully genericized version) of the source object.
+ * @return a JsonElement corresponding to the specified object.
+ */
+ public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonStreamParser.java b/src/org/mcteam/ancientgates/gson/JsonStreamParser.java
new file mode 100644
index 0000000..39ada5b
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonStreamParser.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mcteam.ancientgates.gson;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.mcteam.ancientgates.gson.stream.JsonReader;
+import org.mcteam.ancientgates.gson.stream.JsonToken;
+import org.mcteam.ancientgates.gson.stream.MalformedJsonException;
+
+
+/**
+ * A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
+ * asynchronously.
+ *
+ *
This class is conditionally thread-safe (see Item 70, Effective Java second edition). To
+ * properly use this class across multiple threads, you will need to add some external
+ * synchronization. For example:
+ *
+ *
+ * JsonStreamParser parser = new JsonStreamParser("['first'] {'second':10} 'third'");
+ * JsonElement element;
+ * synchronized (parser) { // synchronize on an object shared by threads
+ * if (parser.hasNext()) {
+ * element = parser.next();
+ * }
+ * }
+ *
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ * @since 1.4
+ */
+public final class JsonStreamParser implements Iterator {
+
+ private final JsonReader parser;
+ private final Object lock;
+
+ /**
+ * @param json The string containing JSON elements concatenated to each other.
+ * @since 1.4
+ */
+ public JsonStreamParser(String json) {
+ this(new StringReader(json));
+ }
+
+ /**
+ * @param reader The data stream containing JSON elements concatenated to each other.
+ * @since 1.4
+ */
+ public JsonStreamParser(Reader reader) {
+ parser = new JsonReader(reader);
+ parser.setLenient(true);
+ lock = new Object();
+ }
+
+ /**
+ * Returns the next available {@link JsonElement} on the reader. Null if none available.
+ *
+ * @return the next available {@link JsonElement} on the reader. Null if none available.
+ * @throws JsonParseException if the incoming stream is malformed JSON.
+ * @since 1.4
+ */
+ public JsonElement next() throws JsonParseException {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ try {
+ return Streams.parse(parser);
+ } catch (StackOverflowError e) {
+ throw new JsonParseException("Failed parsing JSON source to Json", e);
+ } catch (OutOfMemoryError e) {
+ throw new JsonParseException("Failed parsing JSON source to Json", e);
+ } catch (JsonParseException e) {
+ throw e.getCause() instanceof EOFException ? new NoSuchElementException() : e;
+ }
+ }
+
+ /**
+ * Returns true if a {@link JsonElement} is available on the input for consumption
+ * @return true if a {@link JsonElement} is available on the input, false otherwise
+ * @since 1.4
+ */
+ public boolean hasNext() {
+ synchronized (lock) {
+ try {
+ return parser.peek() != JsonToken.END_DOCUMENT;
+ } catch (MalformedJsonException e) {
+ throw new JsonSyntaxException(e);
+ } catch (IOException e) {
+ throw new JsonIOException(e);
+ }
+ }
+ }
+
+ /**
+ * This optional {@link Iterator} method is not relevant for stream parsing and hence is not
+ * implemented.
+ * @since 1.4
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonSyntaxException.java b/src/org/mcteam/ancientgates/gson/JsonSyntaxException.java
new file mode 100644
index 0000000..0082729
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonSyntaxException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mcteam.ancientgates.gson;
+
+/**
+ * This exception is raised when Gson attempts to read (or write) a malformed
+ * JSON element.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public final class JsonSyntaxException extends JsonParseException {
+
+ private static final long serialVersionUID = 1L;
+
+ public JsonSyntaxException(String msg) {
+ super(msg);
+ }
+
+ public JsonSyntaxException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ /**
+ * Creates exception with the specified cause. Consider using
+ * {@link #JsonSyntaxException(String, Throwable)} instead if you can
+ * describe what actually happened.
+ *
+ * @param cause root exception that caused this exception to be thrown.
+ */
+ public JsonSyntaxException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/JsonTreeNavigator.java b/src/org/mcteam/ancientgates/gson/JsonTreeNavigator.java
new file mode 100644
index 0000000..67c1944
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/JsonTreeNavigator.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * A navigator to navigate a tree of JsonElement nodes in Depth-first order
+ *
+ * @author Inderjeet Singh
+ */
+final class JsonTreeNavigator {
+ private final JsonElementVisitor visitor;
+ private final boolean visitNulls;
+
+ JsonTreeNavigator(JsonElementVisitor visitor, boolean visitNulls) {
+ this.visitor = visitor;
+ this.visitNulls = visitNulls;
+ }
+
+ public void navigate(JsonElement element) throws IOException {
+ if (element.isJsonNull()) {
+ visitor.visitNull();
+ } else if (element.isJsonArray()) {
+ JsonArray array = element.getAsJsonArray();
+ visitor.startArray(array);
+ boolean isFirst = true;
+ for (JsonElement child : array) {
+ visitChild(array, child, isFirst);
+ if (isFirst) {
+ isFirst = false;
+ }
+ }
+ visitor.endArray(array);
+ } else if (element.isJsonObject()) {
+ JsonObject object = element.getAsJsonObject();
+ visitor.startObject(object);
+ boolean isFirst = true;
+ for (Map.Entry member : object.entrySet()) {
+ boolean visited = visitChild(object, member.getKey(), member.getValue(), isFirst);
+ if (visited && isFirst) {
+ isFirst = false;
+ }
+ }
+ visitor.endObject(object);
+ } else { // must be JsonPrimitive
+ visitor.visitPrimitive(element.getAsJsonPrimitive());
+ }
+ }
+
+ /**
+ * Returns true if the child was visited, false if it was skipped.
+ */
+ private boolean visitChild(JsonObject parent, String childName, JsonElement child,
+ boolean isFirst) throws IOException {
+ if (child.isJsonNull()) {
+ if (visitNulls) {
+ visitor.visitNullObjectMember(parent, childName, isFirst);
+ navigate(child.getAsJsonNull());
+ } else { // Null value is being skipped.
+ return false;
+ }
+ } else if (child.isJsonArray()) {
+ JsonArray childAsArray = child.getAsJsonArray();
+ visitor.visitObjectMember(parent, childName, childAsArray, isFirst);
+ navigate(childAsArray);
+ } else if (child.isJsonObject()) {
+ JsonObject childAsObject = child.getAsJsonObject();
+ visitor.visitObjectMember(parent, childName, childAsObject, isFirst);
+ navigate(childAsObject);
+ } else { // is a JsonPrimitive
+ visitor.visitObjectMember(parent, childName, child.getAsJsonPrimitive(), isFirst);
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if the child was visited, false if it was skipped.
+ */
+ private void visitChild(JsonArray parent, JsonElement child, boolean isFirst) throws IOException {
+ if (child.isJsonNull()) {
+ visitor.visitNullArrayMember(parent, isFirst);
+ navigate(child);
+ } else if (child.isJsonArray()) {
+ JsonArray childAsArray = child.getAsJsonArray();
+ visitor.visitArrayMember(parent, childAsArray, isFirst);
+ navigate(childAsArray);
+ } else if (child.isJsonObject()) {
+ JsonObject childAsObject = child.getAsJsonObject();
+ visitor.visitArrayMember(parent, childAsObject, isFirst);
+ navigate(childAsObject);
+ } else { // is a JsonPrimitive
+ visitor.visitArrayMember(parent, child.getAsJsonPrimitive(), isFirst);
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/LongSerializationPolicy.java b/src/org/mcteam/ancientgates/gson/LongSerializationPolicy.java
new file mode 100644
index 0000000..bbd4c42
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/LongSerializationPolicy.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * Defines the expected format for a {@code long} or {@code Long} type when its serialized.
+ *
+ * @since 1.3
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+public enum LongSerializationPolicy {
+ /**
+ * This is the "default" serialization policy that will output a {@code long} object as a JSON
+ * number. For example, assume an object has a long field named "f" then the serialized output
+ * would be:
+ * {@code {"f":123}}.
+ */
+ DEFAULT(new DefaultStrategy()),
+
+ /**
+ * Serializes a long value as a quoted string. For example, assume an object has a long field
+ * named "f" then the serialized output would be:
+ * {@code {"f":"123"}}.
+ */
+ STRING(new StringStrategy());
+
+ private final Strategy strategy;
+
+ private LongSerializationPolicy(Strategy strategy) {
+ this.strategy = strategy;
+ }
+
+ /**
+ * Serialize this {@code value} using this serialization policy.
+ *
+ * @param value the long value to be serialized into a {@link JsonElement}
+ * @return the serialized version of {@code value}
+ */
+ public JsonElement serialize(Long value) {
+ return strategy.serialize(value);
+ }
+
+ private interface Strategy {
+ JsonElement serialize(Long value);
+ }
+
+ private static class DefaultStrategy implements Strategy {
+ public JsonElement serialize(Long value) {
+ return new JsonPrimitive(value);
+ }
+ }
+
+ private static class StringStrategy implements Strategy {
+ public JsonElement serialize(Long value) {
+ return new JsonPrimitive(String.valueOf(value));
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/LowerCamelCaseSeparatorNamingPolicy.java b/src/org/mcteam/ancientgates/gson/LowerCamelCaseSeparatorNamingPolicy.java
new file mode 100644
index 0000000..4157504
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/LowerCamelCaseSeparatorNamingPolicy.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
+ * lower case letters and are separated by a particular {@code separatorString}.
+ *
+ *
+ *
+ * @author Joel Leitch
+ */
+final class LowerCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
+
+ public LowerCamelCaseSeparatorNamingPolicy(String separatorString) {
+ super(new CamelCaseSeparatorNamingPolicy(separatorString), new LowerCaseNamingPolicy());
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/LowerCaseNamingPolicy.java b/src/org/mcteam/ancientgates/gson/LowerCaseNamingPolicy.java
new file mode 100644
index 0000000..680464c
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/LowerCaseNamingPolicy.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ * A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
+ * lower case letters.
+ *
+ *
The following is an example:
+ *
+ * class IntWrapper {
+ * public int integerField = 0;
+ * }
+ *
+ * LowerCaseNamingPolicy policy = new LowerCaseNamingPolicy();
+ * String translatedFieldName =
+ * policy.translateName(IntWrapper.class.getField("integerField"));
+ *
+ * assert("integerfield".equals(translatedFieldName));
+ *
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class LowerCaseNamingPolicy extends RecursiveFieldNamingPolicy {
+
+ @Override
+ protected String translateName(String target, Type fieldType,
+ Collection annotations) {
+ return target.toLowerCase();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/LruCache.java b/src/org/mcteam/ancientgates/gson/LruCache.java
new file mode 100644
index 0000000..4533747
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/LruCache.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * An implementation of the {@link Cache} interface that evict objects from the cache using an
+ * LRU (least recently used) algorithm. Object start getting evicted from the cache once the
+ * {@code maxCapacity} is reached.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class LruCache extends LinkedHashMap implements Cache {
+ private static final long serialVersionUID = 1L;
+
+ private final int maxCapacity;
+
+ LruCache(int maxCapacity) {
+ super(maxCapacity, 0.7F, true);
+ this.maxCapacity = maxCapacity;
+ }
+
+ public void addElement(K key, V value) {
+ put(key, value);
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ }
+
+ public V getElement(K key) {
+ return get(key);
+ }
+
+ public V removeElement(K key) {
+ return remove(key);
+ }
+
+ @Override
+ public int size() {
+ return super.size();
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry entry) {
+ return size() > maxCapacity;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/MapAsArrayTypeAdapter.java b/src/org/mcteam/ancientgates/gson/MapAsArrayTypeAdapter.java
new file mode 100644
index 0000000..06f9e58
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/MapAsArrayTypeAdapter.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Adapts maps containing complex keys as arrays of map entries.
+ *
+ *
Maps as JSON objects
+ * The standard GSON map type adapter converts Java {@link Map Maps} to JSON
+ * Objects. This requires that map keys can be serialized as strings; this is
+ * insufficient for some key types. For example, consider a map whose keys are
+ * points on a grid. The default JSON form encodes reasonably:
+ * But GSON is unable to deserialize this value because the JSON string name is
+ * just the {@link Object#toString() toString()} of the map key. Attempting to
+ * convert the above JSON to an object fails with a parse exception:
+ *
com.bukkit.mcteam.gson.JsonParseException: Expecting object found: "(5,6)"
+ * at com.bukkit.mcteam.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
+ * at com.bukkit.mcteam.gson.ObjectNavigator.navigateClassFields
+ * ...
+ *
+ *
Maps as JSON arrays
+ * An alternative approach taken by this type adapter is to encode maps as
+ * arrays of map entries. Each map entry is a two element array containing a key
+ * and a value. This approach is more flexible because any type can be used as
+ * the map's key; not just strings. But it's also less portable because the
+ * receiver of such JSON must be aware of the map entry convention.
+ *
+ *
Register this adapter when you are creating your GSON instance.
+ *
{@code
+ * Gson gson = new GsonBuilder()
+ * .registerTypeAdapter(Map.class, new MapAsArrayTypeAdapter())
+ * .create();
+ * }
+ * 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:
+ *
+ * This format will serialize and deserialize just fine as long as this adapter
+ * is registered.
+ *
+ *
This adapter returns regular JSON objects for maps whose keys are not
+ * complex. A key is complex if its JSON-serialized form is an array or an
+ * object.
+ */
+public final class MapAsArrayTypeAdapter
+ implements JsonSerializer>, JsonDeserializer> {
+
+ public Map, ?> deserialize(JsonElement json, Type typeOfT,
+ JsonDeserializationContext context) throws JsonParseException {
+ Map result = new LinkedHashMap();
+ Type[] keyAndValueType = typeToTypeArguments(typeOfT);
+ if (json.isJsonArray()) {
+ JsonArray array = json.getAsJsonArray();
+ for (int i = 0; i < array.size(); i++) {
+ JsonArray entryArray = array.get(i).getAsJsonArray();
+ Object k = context.deserialize(entryArray.get(0), keyAndValueType[0]);
+ Object v = context.deserialize(entryArray.get(1), keyAndValueType[1]);
+ result.put(k, v);
+ }
+ checkSize(array, array.size(), result, result.size());
+ } else {
+ JsonObject object = json.getAsJsonObject();
+ for (Map.Entry entry : object.entrySet()) {
+ Object k = context.deserialize(new JsonPrimitive(entry.getKey()), keyAndValueType[0]);
+ Object v = context.deserialize(entry.getValue(), keyAndValueType[1]);
+ result.put(k, v);
+ }
+ checkSize(object, object.entrySet().size(), result, result.size());
+ }
+ return result;
+ }
+
+ public JsonElement serialize(Map, ?> src, Type typeOfSrc, JsonSerializationContext context) {
+ Type[] keyAndValueType = typeToTypeArguments(typeOfSrc);
+ boolean serializeAsArray = false;
+ List keysAndValues = new ArrayList();
+ for (Map.Entry, ?> entry : src.entrySet()) {
+ JsonElement key = context.serialize(entry.getKey(), keyAndValueType[0]);
+ serializeAsArray |= key.isJsonObject() || key.isJsonArray();
+ keysAndValues.add(key);
+ keysAndValues.add(context.serialize(entry.getValue(), keyAndValueType[1]));
+ }
+
+ if (serializeAsArray) {
+ JsonArray result = new JsonArray();
+ for (int i = 0; i < keysAndValues.size(); i+=2) {
+ JsonArray entryArray = new JsonArray();
+ entryArray.add(keysAndValues.get(i));
+ entryArray.add(keysAndValues.get(i + 1));
+ result.add(entryArray);
+ }
+ return result;
+ } else {
+ JsonObject result = new JsonObject();
+ for (int i = 0; i < keysAndValues.size(); i+=2) {
+ result.add(keysAndValues.get(i).getAsString(), keysAndValues.get(i + 1));
+ }
+ checkSize(src, src.size(), result, result.entrySet().size());
+ return result;
+ }
+ }
+
+ private Type[] typeToTypeArguments(Type typeOfT) {
+ if (typeOfT instanceof ParameterizedType) {
+ Type[] typeArguments = ((ParameterizedType) typeOfT).getActualTypeArguments();
+ if (typeArguments.length != 2) {
+ throw new IllegalArgumentException("MapAsArrayTypeAdapter cannot handle " + typeOfT);
+ }
+ return typeArguments;
+ }
+ return new Type[] { Object.class, Object.class };
+ }
+
+ private void checkSize(Object input, int inputSize, Object output, int outputSize) {
+ if (inputSize != outputSize) {
+ throw new JsonSyntaxException("Input size " + inputSize + " != output size " + outputSize
+ + " for input " + input + " and output " + output);
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/MappedObjectConstructor.java b/src/org/mcteam/ancientgates/gson/MappedObjectConstructor.java
new file mode 100644
index 0000000..00e14da
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/MappedObjectConstructor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Type;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class contains a mapping of all the application specific
+ * {@link InstanceCreator} instances. Registering an {@link InstanceCreator}
+ * with this class will override the default object creation that is defined
+ * by the ObjectConstructor that this class is wrapping. Using this class
+ * with the JSON framework provides the application with "pluggable" modules
+ * to customize framework to suit the application's needs.
+ *
+ * @author Joel Leitch
+ */
+final class MappedObjectConstructor implements ObjectConstructor {
+ private static final Logger log = Logger.getLogger(MappedObjectConstructor.class.getName());
+
+ private final ParameterizedTypeHandlerMap> instanceCreatorMap;
+
+ public MappedObjectConstructor(
+ ParameterizedTypeHandlerMap> instanceCreators) {
+ instanceCreatorMap = instanceCreators;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T construct(Type typeOfT) {
+ InstanceCreator creator = (InstanceCreator) instanceCreatorMap.getHandlerFor(typeOfT);
+ if (creator != null) {
+ return creator.createInstance(typeOfT);
+ }
+ return (T) constructWithNoArgConstructor(typeOfT);
+ }
+
+ public Object constructArray(Type type, int length) {
+ return Array.newInstance(TypeUtils.toRawClass(type), length);
+ }
+
+ private T constructWithNoArgConstructor(Type typeOfT) {
+ try {
+ Constructor constructor = getNoArgsConstructor(typeOfT);
+ if (constructor == null) {
+ throw new RuntimeException(("No-args constructor for " + typeOfT + " does not exist. "
+ + "Register an InstanceCreator with Gson for this type to fix this problem."));
+ }
+ return constructor.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
+ + "Register an InstanceCreator with Gson for this type may fix this problem."), e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
+ + "Register an InstanceCreator with Gson for this type may fix this problem."), e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
+ + "Register an InstanceCreator with Gson for this type may fix this problem."), e);
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "cast"})
+ private Constructor getNoArgsConstructor(Type typeOfT) {
+ TypeInfo typeInfo = new TypeInfo(typeOfT);
+ Class clazz = (Class) typeInfo.getRawClass();
+ Constructor[] declaredConstructors = (Constructor[]) clazz.getDeclaredConstructors();
+ AccessibleObject.setAccessible(declaredConstructors, true);
+ for (Constructor constructor : declaredConstructors) {
+ if (constructor.getParameterTypes().length == 0) {
+ return constructor;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Use this methods to register an {@link InstanceCreator} for a new type.
+ *
+ * @param the type of class to be mapped with its "creator"
+ * @param typeOfT the instance type that will be created
+ * @param creator the {@link InstanceCreator} instance to register
+ */
+ void register(Type typeOfT, InstanceCreator extends T> creator) {
+ if (instanceCreatorMap.hasSpecificHandlerFor(typeOfT)) {
+ log.log(Level.WARNING, "Overriding the existing InstanceCreator for {0}", typeOfT);
+ }
+ instanceCreatorMap.register(typeOfT, creator);
+ }
+
+ @Override
+ public String toString() {
+ return instanceCreatorMap.toString();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/MemoryRefStack.java b/src/org/mcteam/ancientgates/gson/MemoryRefStack.java
new file mode 100644
index 0000000..7de13a7
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/MemoryRefStack.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.util.Stack;
+
+/**
+ * A stack data structure that only does a memory reference comparison
+ * when looking for a particular item in the stack. This stack does
+ * not allow {@code null} values to be added.
+ *
+ * @author Joel Leitch
+ */
+final class MemoryRefStack {
+ private final Stack stack = new Stack();
+
+ /**
+ * Adds a new element to the top of the stack.
+ *
+ * @param obj the object to add to the stack
+ * @return the object that was added
+ */
+ public ObjectTypePair push(ObjectTypePair obj) {
+ Preconditions.checkNotNull(obj);
+
+ return stack.push(obj);
+ }
+
+ /**
+ * Removes the top element from the stack.
+ *
+ * @return the element being removed from the stack
+ * @throws java.util.EmptyStackException thrown if the stack is empty
+ */
+ public ObjectTypePair pop() {
+ return stack.pop();
+ }
+
+ public boolean isEmpty() {
+ return stack.isEmpty();
+ }
+
+ /**
+ * Retrieves the item from the top of the stack, but does not remove it.
+ *
+ * @return the item from the top of the stack
+ * @throws java.util.EmptyStackException thrown if the stack is empty
+ */
+ public ObjectTypePair peek() {
+ return stack.peek();
+ }
+
+ /**
+ * Performs a memory reference check to see it the {@code obj} exists in
+ * the stack.
+ *
+ * @param obj the object to search for in the stack
+ * @return true if this object is already in the stack otherwise false
+ */
+ public boolean contains(ObjectTypePair obj) {
+ if (obj == null) {
+ return false;
+ }
+
+ for (ObjectTypePair stackObject : stack) {
+ if (stackObject.getObject() == obj.getObject()
+ && stackObject.type.equals(obj.type) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ModifierBasedExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/ModifierBasedExclusionStrategy.java
new file mode 100644
index 0000000..ddb3ac9
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ModifierBasedExclusionStrategy.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * Exclude fields based on particular field modifiers. For a list of possible
+ * modifiers, see {@link java.lang.reflect.Modifier}.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class ModifierBasedExclusionStrategy implements ExclusionStrategy {
+ private final Collection modifiers;
+
+ public ModifierBasedExclusionStrategy(int... modifiers) {
+ this.modifiers = new HashSet();
+ if (modifiers != null) {
+ for (int modifier : modifiers) {
+ this.modifiers.add(modifier);
+ }
+ }
+ }
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ for (int modifier : modifiers) {
+ if (f.hasModifier(modifier)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean shouldSkipClass(Class> clazz) {
+ return false;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy.java b/src/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy.java
new file mode 100644
index 0000000..45554a9
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ModifyFirstLetterNamingPolicy.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ * A {@link FieldNamingStrategy2} that ensures the JSON field names begins with
+ * an upper case letter.
+ *
+ *
+ *
+ * @author Joel Leitch
+ */
+final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
+
+ public enum LetterModifier {
+ UPPER,
+ LOWER;
+ }
+
+ private final LetterModifier letterModifier;
+
+ /**
+ * Creates a new ModifyFirstLetterNamingPolicy that will either modify the first letter of the
+ * target name to either UPPER case or LOWER case depending on the {@code modifier} parameter.
+ *
+ * @param modifier the type of modification that should be performed
+ * @throws IllegalArgumentException if {@code modifier} is null
+ */
+ public ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
+ Preconditions.checkNotNull(modifier);
+ this.letterModifier = modifier;
+ }
+
+ @Override
+ protected String translateName(String target, Type fieldType,
+ Collection annotations) {
+ StringBuilder fieldNameBuilder = new StringBuilder();
+ int index = 0;
+ char firstCharacter = target.charAt(index);
+
+ while (index < target.length() - 1) {
+ if (Character.isLetter(firstCharacter)) {
+ break;
+ }
+
+ fieldNameBuilder.append(firstCharacter);
+ firstCharacter = target.charAt(++index);
+ }
+
+ if (index == target.length()) {
+ return fieldNameBuilder.toString();
+ }
+
+ boolean capitalizeFirstLetter = (letterModifier == LetterModifier.UPPER);
+ if (capitalizeFirstLetter && !Character.isUpperCase(firstCharacter)) {
+ String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), target, ++index);
+ return fieldNameBuilder.append(modifiedTarget).toString();
+ } else if (!capitalizeFirstLetter && Character.isUpperCase(firstCharacter)) {
+ String modifiedTarget = modifyString(Character.toLowerCase(firstCharacter), target, ++index);
+ return fieldNameBuilder.append(modifiedTarget).toString();
+ } else {
+ return target;
+ }
+ }
+
+ private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
+ return indexOfSubstring < srcString.length() ?
+ firstCharacter + srcString.substring(indexOfSubstring)
+ : String.valueOf(firstCharacter);
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/NullExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/NullExclusionStrategy.java
new file mode 100644
index 0000000..8e1cedc
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/NullExclusionStrategy.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+
+/**
+ * This acts as a "Null Object" pattern for the {@link ExclusionStrategy}.
+ * Passing an instance of this class into the {@link ObjectNavigator} will
+ * make the {@link ObjectNavigator} parse/visit every field of the object
+ * being navigated.
+ *
+ * @author Joel Leitch
+ */
+final class NullExclusionStrategy implements ExclusionStrategy {
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ return false;
+ }
+
+ public boolean shouldSkipClass(Class> clazz) {
+ return false;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ObjectConstructor.java b/src/org/mcteam/ancientgates/gson/ObjectConstructor.java
new file mode 100644
index 0000000..8c8e9eb
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ObjectConstructor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * Defines a generic object construction factory. The purpose of this class
+ * is to construct a default instance of a class that can be used for object
+ * navigation while deserialization from its JSON representation.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+interface ObjectConstructor {
+
+ /**
+ * Creates a new instance of the given type.
+ *
+ * @param typeOfT the class type that should be instantiated
+ * @return a default instance of the provided class.
+ */
+ public T construct(Type typeOfT);
+
+ /**
+ * Constructs an array type of the provided length.
+ *
+ * @param typeOfArrayElements type of objects in the array
+ * @param length size of the array
+ * @return new array of size length
+ */
+ public Object constructArray(Type typeOfArrayElements, int length);
+}
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/ObjectNavigator.java b/src/org/mcteam/ancientgates/gson/ObjectNavigator.java
new file mode 100644
index 0000000..b5f3964
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ObjectNavigator.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+
+/**
+ * Provides ability to apply a visitor to an object and all of its fields
+ * recursively.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class ObjectNavigator {
+
+ public interface Visitor {
+ public void start(ObjectTypePair node);
+
+ public void end(ObjectTypePair node);
+
+ /**
+ * This is called before the object navigator starts visiting the current
+ * object
+ */
+ void startVisitingObject(Object node);
+
+ /**
+ * This is called to visit the current object if it is an array
+ */
+ void visitArray(Object array, Type componentType);
+
+ /**
+ * This is called to visit an object field of the current object
+ */
+ void visitObjectField(FieldAttributes f, Type typeOfF, Object obj);
+
+ /**
+ * This is called to visit an array field of the current object
+ */
+ void visitArrayField(FieldAttributes f, Type typeOfF, Object obj);
+
+ /**
+ * This is called to visit an object using a custom handler
+ *
+ * @return true if a custom handler exists, false otherwise
+ */
+ public boolean visitUsingCustomHandler(ObjectTypePair objTypePair);
+
+ /**
+ * This is called to visit a field of the current object using a custom
+ * handler
+ */
+ public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField,
+ Object parent);
+
+ /**
+ * Retrieve the current target
+ */
+ Object getTarget();
+
+ void visitPrimitive(Object primitive);
+ }
+
+ private final ExclusionStrategy exclusionStrategy;
+ private final ObjectTypePair objTypePair;
+
+ /**
+ * @param objTypePair
+ * The object,type (fully genericized) being navigated
+ * @param exclusionStrategy
+ * the concrete strategy object to be used to filter out fields of an
+ * object.
+ */
+ ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) {
+ Preconditions.checkNotNull(exclusionStrategy);
+
+ this.objTypePair = objTypePair;
+ this.exclusionStrategy = exclusionStrategy;
+ }
+
+ /**
+ * Navigate all the fields of the specified object. If a field is null, it
+ * does not get visited.
+ */
+ public void accept(Visitor visitor) {
+ TypeInfo objTypeInfo = new TypeInfo(objTypePair.type);
+ if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
+ return;
+ }
+ boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
+ if (!visitedWithCustomHandler) {
+ Object obj = objTypePair.getObject();
+ Object objectToVisit = (obj == null) ? visitor.getTarget() : obj;
+ if (objectToVisit == null) {
+ return;
+ }
+ objTypePair.setObject(objectToVisit);
+ visitor.start(objTypePair);
+ try {
+ if (objTypeInfo.isArray()) {
+ visitor.visitArray(objectToVisit, objTypePair.type);
+ } else if (objTypeInfo.getActualType() == Object.class
+ && isPrimitiveOrString(objectToVisit)) {
+ // TODO(Joel): this is only used for deserialization of "primitives"
+ // we should rethink this!!!
+ visitor.visitPrimitive(objectToVisit);
+ objectToVisit = visitor.getTarget();
+ } else {
+ visitor.startVisitingObject(objectToVisit);
+ ObjectTypePair currObjTypePair = objTypePair.toMoreSpecificType();
+ Class> topLevelClass = new TypeInfo(currObjTypePair.type).getRawClass();
+ for (Class> curr = topLevelClass; curr != null && !curr.equals(Object.class); curr =
+ curr.getSuperclass()) {
+ if (!curr.isSynthetic()) {
+ navigateClassFields(objectToVisit, curr, visitor);
+ }
+ }
+ }
+ } finally {
+ visitor.end(objTypePair);
+ }
+ }
+ }
+
+ private boolean isPrimitiveOrString(Object objectToVisit) {
+ Class> realClazz = objectToVisit.getClass();
+ return realClazz == Object.class || realClazz == String.class
+ || Primitives.unwrap(realClazz).isPrimitive();
+ }
+
+ private void navigateClassFields(Object obj, Class> clazz, Visitor visitor) {
+ Field[] fields = clazz.getDeclaredFields();
+ AccessibleObject.setAccessible(fields, true);
+ for (Field f : fields) {
+ FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
+ if (exclusionStrategy.shouldSkipField(fieldAttributes)
+ || exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
+ continue; // skip
+ }
+ TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.type);
+ Type declaredTypeOfField = fieldTypeInfo.getActualType();
+ boolean visitedWithCustomHandler =
+ visitor.visitFieldUsingCustomHandler(fieldAttributes, declaredTypeOfField, obj);
+ if (!visitedWithCustomHandler) {
+ if (fieldTypeInfo.isArray()) {
+ visitor.visitArrayField(fieldAttributes, declaredTypeOfField, obj);
+ } else {
+ visitor.visitObjectField(fieldAttributes, declaredTypeOfField, obj);
+ }
+ }
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ObjectNavigatorFactory.java b/src/org/mcteam/ancientgates/gson/ObjectNavigatorFactory.java
new file mode 100644
index 0000000..02dcff7
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ObjectNavigatorFactory.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * A factory class used to simplify {@link ObjectNavigator} creation.
+ * This object holds on to a reference of the {@link ExclusionStrategy}
+ * that you'd like to use with the {@link ObjectNavigator}.
+ *
+ * @author Joel Leitch
+ */
+final class ObjectNavigatorFactory {
+ private final ExclusionStrategy strategy;
+ private final FieldNamingStrategy2 fieldNamingPolicy;
+
+ /**
+ * Creates a factory object that will be able to create new
+ * {@link ObjectNavigator}s with the provided {@code strategy}
+ *
+ * @param strategy the exclusion strategy to use with every instance that
+ * is created by this factory instance.
+ * @param fieldNamingPolicy the naming policy that should be applied to field
+ * names
+ */
+ public ObjectNavigatorFactory(ExclusionStrategy strategy, FieldNamingStrategy2 fieldNamingPolicy) {
+ Preconditions.checkNotNull(fieldNamingPolicy);
+ this.strategy = (strategy == null ? new NullExclusionStrategy() : strategy);
+ this.fieldNamingPolicy = fieldNamingPolicy;
+ }
+
+ /**
+ * Creates a new {@link ObjectNavigator} for this {@code srcObject},
+ * {@code type} pair.
+ *
+ * @param objTypePair The object,type (fully genericized) being navigated
+ * @return a new instance of a {@link ObjectNavigator} ready to navigate the
+ * {@code srcObject} while taking into consideration the
+ * {@code type}.
+ */
+ public ObjectNavigator create(ObjectTypePair objTypePair) {
+ return new ObjectNavigator(objTypePair, strategy);
+ }
+
+ FieldNamingStrategy2 getFieldNamingPolicy() {
+ return fieldNamingPolicy;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ObjectTypePair.java b/src/org/mcteam/ancientgates/gson/ObjectTypePair.java
new file mode 100644
index 0000000..5f3ad99
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ObjectTypePair.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+
+/**
+ * A holder class for an object and its type
+ *
+ * @author Inderjeet Singh
+ */
+final class ObjectTypePair {
+ private Object obj;
+ final Type type;
+ private final boolean preserveType;
+
+ ObjectTypePair(Object obj, Type type, boolean preserveType) {
+ this.obj = obj;
+ this.type = type;
+ this.preserveType = preserveType;
+ }
+
+ Object getObject() {
+ return obj;
+ }
+
+ void setObject(Object obj) {
+ this.obj = obj;
+ }
+
+ Type getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("preserveType: %b, type: %s, obj: %s", preserveType, type, obj);
+ }
+
+ Pair getMatchingHandler(
+ ParameterizedTypeHandlerMap handlers) {
+ HANDLER handler = null;
+ if (!preserveType && obj != null) {
+ // First try looking up the handler for the actual type
+ ObjectTypePair moreSpecificType = toMoreSpecificType();
+ handler = handlers.getHandlerFor(moreSpecificType.type);
+ if (handler != null) {
+ return new Pair(handler, moreSpecificType);
+ }
+ }
+ // Try the specified type
+ handler = handlers.getHandlerFor(type);
+ return handler == null ? null : new Pair(handler, this);
+ }
+
+ ObjectTypePair toMoreSpecificType() {
+ if (preserveType || obj == null) {
+ return this;
+ }
+ Type actualType = getActualTypeIfMoreSpecific(type, obj.getClass());
+ if (actualType == type) {
+ return this;
+ }
+ return new ObjectTypePair(obj, actualType, preserveType);
+ }
+
+ // This takes care of situations where the field was declared as an Object, but the
+ // actual value contains something more specific. See Issue 54.
+ // TODO (inder): This solution will not work if the field is of a generic type, but
+ // the actual object is of a raw type (which is a sub-class of the generic type).
+ static Type getActualTypeIfMoreSpecific(Type type, Class> actualClass) {
+ if (type instanceof Class>) {
+ Class> typeAsClass = (Class>) type;
+ if (typeAsClass.isAssignableFrom(actualClass)) {
+ type = actualClass;
+ }
+ if (type == Object.class) {
+ type = actualClass;
+ }
+ }
+ return type;
+ }
+
+ @Override
+ public int hashCode() {
+ // Not using type.hashCode() since I am not sure if the subclasses of type reimplement
+ // hashCode() to be equal for equal types
+ return ((obj == null) ? 31 : obj.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ObjectTypePair other = (ObjectTypePair) obj;
+ if (this.obj == null) {
+ if (other.obj != null) {
+ return false;
+ }
+ } else if (this.obj != other.obj) { // Checking for reference equality
+ return false;
+ }
+ if (type == null) {
+ if (other.type != null) {
+ return false;
+ }
+ } else if (!type.equals(other.type)) {
+ return false;
+ }
+ return preserveType == other.preserveType;
+ }
+
+ public boolean isPreserveType() {
+ return preserveType;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/Pair.java b/src/org/mcteam/ancientgates/gson/Pair.java
new file mode 100644
index 0000000..ff95ae8
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/Pair.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * A simple object that holds onto a pair of object references, first and second.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ *
+ * @param
+ * @param
+ */
+final class Pair {
+
+ final FIRST first;
+ final SECOND second;
+
+ Pair(FIRST first, SECOND second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ @Override
+ public int hashCode() {
+ return 17 * ((first != null) ? first.hashCode() : 0)
+ + 17 * ((second != null) ? second.hashCode() : 0);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Pair, ?>)) {
+ return false;
+ }
+
+ Pair, ?> that = (Pair, ?>) o;
+ return equal(this.first, that.first) && equal(this.second, that.second);
+ }
+
+ private static boolean equal(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{%s,%s}", first, second);
+ }
+}
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/ParameterizedTypeHandlerMap.java b/src/org/mcteam/ancientgates/gson/ParameterizedTypeHandlerMap.java
new file mode 100644
index 0000000..ebb5a31
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ParameterizedTypeHandlerMap.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A map that provides ability to associate handlers for a specific type or all
+ * of its sub-types
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ *
+ * @param The handler that will be looked up by type
+ */
+final class ParameterizedTypeHandlerMap {
+ private static final Logger logger =
+ Logger.getLogger(ParameterizedTypeHandlerMap.class.getName());
+ private final Map map = new HashMap();
+ private final List, T>> typeHierarchyList = new ArrayList, T>>();
+ private boolean modifiable = true;
+
+ public synchronized void registerForTypeHierarchy(Class> typeOfT, T value) {
+ Pair, T> pair = new Pair, T>(typeOfT, value);
+ registerForTypeHierarchy(pair);
+ }
+
+ public synchronized void registerForTypeHierarchy(Pair, T> pair) {
+ if (!modifiable) {
+ throw new IllegalStateException("Attempted to modify an unmodifiable map.");
+ }
+ int index = getIndexOfSpecificHandlerForTypeHierarchy(pair.first);
+ if (index >= 0) {
+ logger.log(Level.WARNING, "Overriding the existing type handler for {0}", pair.first);
+ typeHierarchyList.remove(index);
+ }
+ index = getIndexOfAnOverriddenHandler(pair.first);
+ if (index >= 0) {
+ throw new IllegalArgumentException("The specified type handler for type " + pair.first
+ + " hides the previously registered type hierarchy handler for "
+ + typeHierarchyList.get(index).first + ". Gson does not allow this.");
+ }
+ // We want stack behavior for adding to this list. A type adapter added subsequently should
+ // override a previously registered one.
+ typeHierarchyList.add(0, pair);
+ }
+
+ private int getIndexOfAnOverriddenHandler(Class> type) {
+ for (int i = typeHierarchyList.size()-1; i >= 0; --i) {
+ Pair, T> entry = typeHierarchyList.get(i);
+ if (type.isAssignableFrom(entry.first)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public synchronized void register(Type typeOfT, T value) {
+ if (!modifiable) {
+ throw new IllegalStateException("Attempted to modify an unmodifiable map.");
+ }
+ if (hasSpecificHandlerFor(typeOfT)) {
+ logger.log(Level.WARNING, "Overriding the existing type handler for {0}", typeOfT);
+ }
+ map.put(typeOfT, value);
+ }
+
+ public synchronized void registerIfAbsent(ParameterizedTypeHandlerMap other) {
+ if (!modifiable) {
+ throw new IllegalStateException("Attempted to modify an unmodifiable map.");
+ }
+ for (Map.Entry entry : other.map.entrySet()) {
+ if (!map.containsKey(entry.getKey())) {
+ register(entry.getKey(), entry.getValue());
+ }
+ }
+ // Quite important to traverse the typeHierarchyList from stack bottom first since
+ // we want to register the handlers in the same order to preserve priority order
+ for (int i = other.typeHierarchyList.size()-1; i >= 0; --i) {
+ Pair, T> entry = other.typeHierarchyList.get(i);
+ int index = getIndexOfSpecificHandlerForTypeHierarchy(entry.first);
+ if (index < 0) {
+ registerForTypeHierarchy(entry);
+ }
+ }
+ }
+
+ public synchronized void registerIfAbsent(Type typeOfT, T value) {
+ if (!modifiable) {
+ throw new IllegalStateException("Attempted to modify an unmodifiable map.");
+ }
+ if (!map.containsKey(typeOfT)) {
+ register(typeOfT, value);
+ }
+ }
+
+ public synchronized void makeUnmodifiable() {
+ modifiable = false;
+ }
+
+ public synchronized T getHandlerFor(Type type) {
+ T handler = map.get(type);
+ if (handler == null) {
+ Class> rawClass = TypeUtils.toRawClass(type);
+ if (rawClass != type) {
+ handler = getHandlerFor(rawClass);
+ }
+ if (handler == null) {
+ // check if something registered for type hierarchy
+ handler = getHandlerForTypeHierarchy(rawClass);
+ }
+ }
+ return handler;
+ }
+
+ private T getHandlerForTypeHierarchy(Class> type) {
+ for (Pair, T> entry : typeHierarchyList) {
+ if (entry.first.isAssignableFrom(type)) {
+ return entry.second;
+ }
+ }
+ return null;
+ }
+
+ public synchronized boolean hasSpecificHandlerFor(Type type) {
+ return map.containsKey(type);
+ }
+
+ private synchronized int getIndexOfSpecificHandlerForTypeHierarchy(Class> type) {
+ for (int i = typeHierarchyList.size()-1; i >= 0; --i) {
+ if (type.equals(typeHierarchyList.get(i).first)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public synchronized ParameterizedTypeHandlerMap copyOf() {
+ ParameterizedTypeHandlerMap copy = new ParameterizedTypeHandlerMap();
+ for (Map.Entry entry : map.entrySet()) {
+ copy.register(entry.getKey(), entry.getValue());
+ }
+ for (Pair, T> entry : typeHierarchyList) {
+ copy.registerForTypeHierarchy(entry);
+ }
+ return copy;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("{mapForTypeHierarchy:{");
+ boolean first = true;
+ for (Pair, T> entry : typeHierarchyList) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(typeToString(entry.first)).append(':');
+ sb.append(entry.second);
+ }
+ sb.append("},map:{");
+ first = true;
+ for (Map.Entry entry : map.entrySet()) {
+ if (first) {
+ first = false;
+ } else {
+ sb.append(',');
+ }
+ sb.append(typeToString(entry.getKey())).append(':');
+ sb.append(entry.getValue());
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private String typeToString(Type type) {
+ return TypeUtils.toRawClass(type).getSimpleName();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/ParameterizedTypeImpl.java b/src/org/mcteam/ancientgates/gson/ParameterizedTypeImpl.java
new file mode 100644
index 0000000..891df01
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/ParameterizedTypeImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+/**
+ * An immutable implementation of the {@link ParameterizedType} interface. This object allows
+ * us to build a reflective {@link Type} objects on demand. This object is used to support
+ * serialization and deserialization of classes with an {@code ParameterizedType} field where
+ * as least one of the actual type parameters is a {@code TypeVariable}.
+ *
+ *
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+final class ParameterizedTypeImpl implements ParameterizedType {
+
+ private final Type rawType;
+ private final Type[] actualTypeArguments;
+ private final Type owner;
+
+ public ParameterizedTypeImpl(Type rawType, Type[] actualTypeArguments, Type owner) {
+ this.rawType = rawType;
+ this.actualTypeArguments = actualTypeArguments;
+ this.owner = owner;
+ }
+
+ public Type getRawType() {
+ return rawType;
+ }
+
+ public Type[] getActualTypeArguments() {
+ return actualTypeArguments;
+ }
+
+ public Type getOwnerType() {
+ return owner;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ParameterizedType)) {
+ return false;
+ }
+ // Check that information is equivalent
+ ParameterizedType that = (ParameterizedType) o;
+ if (this == that) {
+ return true;
+ }
+ Type thatOwner = that.getOwnerType();
+ Type thatRawType = that.getRawType();
+
+ return (owner == null ? thatOwner == null : owner.equals(thatOwner))
+ && (rawType == null ? thatRawType == null : rawType.equals(thatRawType))
+ && Arrays.equals(actualTypeArguments, that.getActualTypeArguments());
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(actualTypeArguments)
+ ^ (owner == null ? 0 : owner.hashCode())
+ ^ (rawType == null ? 0 : rawType.hashCode());
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/Preconditions.java b/src/org/mcteam/ancientgates/gson/Preconditions.java
new file mode 100644
index 0000000..178d3af
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/Preconditions.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * A simple utility class used to check method Preconditions.
+ *
+ *
+ */
+ public static Class wrap(Class type) {
+ checkNotNull(type);
+
+ // cast is safe: long.class and Long.class are both of type Class
+ @SuppressWarnings("unchecked")
+ Class wrapped = (Class) PRIMITIVE_TO_WRAPPER_TYPE.get(type);
+ return (wrapped == null) ? type : wrapped;
+ }
+
+ /**
+ * Returns the corresponding primitive type of {@code type} if it is a
+ * wrapper type; otherwise returns {@code type} itself. Idempotent.
+ *
+ */
+ public static Class unwrap(Class type) {
+ checkNotNull(type);
+
+ // cast is safe: long.class and Long.class are both of type Class
+ @SuppressWarnings("unchecked")
+ Class unwrapped = (Class) WRAPPER_TO_PRIMITIVE_TYPE.get(type);
+ return (unwrapped == null) ? type : unwrapped;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/RecursiveFieldNamingPolicy.java b/src/org/mcteam/ancientgates/gson/RecursiveFieldNamingPolicy.java
new file mode 100644
index 0000000..1d0062a
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/RecursiveFieldNamingPolicy.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ * A mechanism for providing custom field naming in Gson. This allows the client code to translate
+ * field names into a particular convention that is not supported as a normal Java field
+ * declaration rules. For example, Java does not support "-" characters in a field name.
+ *
+ * @author Joel Leitch
+ */
+abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 {
+
+ public final String translateName(FieldAttributes f) {
+ Preconditions.checkNotNull(f);
+ return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations());
+ }
+
+ /**
+ * Performs the specific string translation.
+ *
+ * @param target the string object that will be manipulation/translated
+ * @param fieldType the actual type value of the field
+ * @param annotations the annotations set on the field
+ * @return the translated field name
+ */
+ protected abstract String translateName(String target, Type fieldType, Collection annotations);
+}
diff --git a/src/org/mcteam/ancientgates/gson/SerializedNameAnnotationInterceptingNamingPolicy.java b/src/org/mcteam/ancientgates/gson/SerializedNameAnnotationInterceptingNamingPolicy.java
new file mode 100644
index 0000000..6ab6756
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/SerializedNameAnnotationInterceptingNamingPolicy.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import org.mcteam.ancientgates.gson.annotations.SerializedName;
+
+/**
+ * A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the
+ * {@link org.mcteam.ancientgates.gson.annotations.SerializedName} annotation is applied to a field then this
+ * strategy will translate the name to the {@code serializedName.value()}; otherwise it delegates
+ * to the wrapped {@link FieldNamingStrategy2}.
+ *
+ *
NOTE: this class performs JSON field name validation for any of the fields marked with
+ * an {@code @SerializedName} annotation.
+ *
+ * @see SerializedName
+ *
+ * @author Joel Leitch
+ */
+final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 {
+ private static final JsonFieldNameValidator fieldNameValidator = new JsonFieldNameValidator();
+ private final FieldNamingStrategy2 delegate;
+
+ public SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
+ this.delegate = delegate;
+ }
+
+ public String translateName(FieldAttributes f) {
+ Preconditions.checkNotNull(f);
+ SerializedName serializedName = f.getAnnotation(SerializedName.class);
+ return serializedName == null ? delegate.translateName(f)
+ : fieldNameValidator.validate(serializedName.value());
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/Streams.java b/src/org/mcteam/ancientgates/gson/Streams.java
new file mode 100644
index 0000000..2b77d84
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/Streams.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import org.mcteam.ancientgates.gson.stream.JsonReader;
+import org.mcteam.ancientgates.gson.stream.JsonWriter;
+import org.mcteam.ancientgates.gson.stream.MalformedJsonException;
+
+/**
+ * Reads and writes GSON parse trees over streams.
+ */
+final class Streams {
+
+ /**
+ * Takes a reader in any state and returns the next value as a JsonElement.
+ */
+ static JsonElement parse(JsonReader reader) throws JsonParseException {
+ boolean isEmpty = true;
+ try {
+ reader.peek();
+ isEmpty = false;
+ return parseRecursive(reader);
+ } catch (EOFException e) {
+ /*
+ * For compatibility with JSON 1.5 and earlier, we return a JsonNull for
+ * empty documents instead of throwing.
+ */
+ if (isEmpty) {
+ return JsonNull.createJsonNull();
+ }
+ throw new JsonIOException(e);
+ } catch (MalformedJsonException e) {
+ throw new JsonSyntaxException(e);
+ } catch (IOException e) {
+ throw new JsonIOException(e);
+ } catch (NumberFormatException e) {
+ throw new JsonSyntaxException(e);
+ }
+ }
+
+ private static JsonElement parseRecursive(JsonReader reader) throws IOException {
+ switch (reader.peek()) {
+ case STRING:
+ return new JsonPrimitive(reader.nextString());
+ case NUMBER:
+ String number = reader.nextString();
+ return new JsonPrimitive(JsonPrimitive.stringToNumber(number));
+ case BOOLEAN:
+ return new JsonPrimitive(reader.nextBoolean());
+ case NULL:
+ reader.nextNull();
+ return JsonNull.createJsonNull();
+ case BEGIN_ARRAY:
+ JsonArray array = new JsonArray();
+ reader.beginArray();
+ while (reader.hasNext()) {
+ array.add(parseRecursive(reader));
+ }
+ reader.endArray();
+ return array;
+ case BEGIN_OBJECT:
+ JsonObject object = new JsonObject();
+ reader.beginObject();
+ while (reader.hasNext()) {
+ object.add(reader.nextName(), parseRecursive(reader));
+ }
+ reader.endObject();
+ return object;
+ case END_DOCUMENT:
+ case NAME:
+ case END_OBJECT:
+ case END_ARRAY:
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Writes the JSON element to the writer, recursively.
+ */
+ static void write(JsonElement element, boolean serializeNulls, JsonWriter writer)
+ throws IOException {
+ if (element == null || element.isJsonNull()) {
+ if (serializeNulls) {
+ writer.nullValue();
+ }
+
+ } else if (element.isJsonPrimitive()) {
+ JsonPrimitive primitive = element.getAsJsonPrimitive();
+ if (primitive.isNumber()) {
+ writer.value(primitive.getAsNumber());
+ } else if (primitive.isBoolean()) {
+ writer.value(primitive.getAsBoolean());
+ } else {
+ writer.value(primitive.getAsString());
+ }
+
+ } else if (element.isJsonArray()) {
+ writer.beginArray();
+ for (JsonElement e : element.getAsJsonArray()) {
+ /* always print null when its parent element is an array! */
+ if (e.isJsonNull()) {
+ writer.nullValue();
+ continue;
+ }
+ write(e, serializeNulls, writer);
+ }
+ writer.endArray();
+
+ } else if (element.isJsonObject()) {
+ writer.beginObject();
+ for (Map.Entry e : element.getAsJsonObject().entrySet()) {
+ JsonElement value = e.getValue();
+ if (!serializeNulls && value.isJsonNull()) {
+ continue;
+ }
+ writer.name(e.getKey());
+ write(value, serializeNulls, writer);
+ }
+ writer.endObject();
+
+ } else {
+ throw new IllegalArgumentException("Couldn't write " + element.getClass());
+ }
+ }
+
+ static Writer writerForAppendable(Appendable appendable) {
+ return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable);
+ }
+
+ /**
+ * Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer}
+ * is used.
+ */
+ private static class AppendableWriter extends Writer {
+ private final Appendable appendable;
+ private final CurrentWrite currentWrite = new CurrentWrite();
+
+ private AppendableWriter(Appendable appendable) {
+ this.appendable = appendable;
+ }
+
+ @Override public void write(char[] chars, int offset, int length) throws IOException {
+ currentWrite.chars = chars;
+ appendable.append(currentWrite, offset, offset + length);
+ }
+
+ @Override public void write(int i) throws IOException {
+ appendable.append((char) i);
+ }
+
+ @Override public void flush() {}
+ @Override public void close() {}
+
+ /**
+ * A mutable char sequence pointing at a single char[].
+ */
+ static class CurrentWrite implements CharSequence {
+ char[] chars;
+ public int length() {
+ return chars.length;
+ }
+ public char charAt(int i) {
+ return chars[i];
+ }
+ public CharSequence subSequence(int start, int end) {
+ return new String(chars, start, end - start);
+ }
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/SyntheticFieldExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/SyntheticFieldExclusionStrategy.java
new file mode 100644
index 0000000..ff61e82
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/SyntheticFieldExclusionStrategy.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * A data object that stores attributes of a field.
+ *
+ *
This class is immutable; therefore, it can be safely shared across threads.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ *
+ * @since 1.4
+ */
+class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
+ private final boolean skipSyntheticFields;
+
+ SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) {
+ this.skipSyntheticFields = skipSyntheticFields;
+ }
+
+ public boolean shouldSkipClass(Class> clazz) {
+ return false;
+ }
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ return skipSyntheticFields && f.isSynthetic();
+ }
+
+}
diff --git a/src/org/mcteam/ancientgates/gson/TypeAdapter.java b/src/org/mcteam/ancientgates/gson/TypeAdapter.java
new file mode 100644
index 0000000..d06248c
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/TypeAdapter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * This class is responsible for adapting/converting an particular "from"
+ * instance to an instance of type "to".
+ *
+ * @author Joel Leitch
+ */
+interface TypeAdapter {
+
+ /**
+ * Adapts an object instance "from" to and instance of type "to".
+ *
+ * @param from the object to adapt
+ * @param to the Type/Class which this will convert to
+ * @return the converted "from" instance to type "to"
+ */
+ public T adaptType(Object from, Class to);
+}
diff --git a/src/org/mcteam/ancientgates/gson/TypeInfo.java b/src/org/mcteam/ancientgates/gson/TypeInfo.java
new file mode 100644
index 0000000..d292e39
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/TypeInfo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ * Class that provides information relevant to different parts of a type.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+class TypeInfo {
+ protected final Type actualType;
+ protected final Class> rawClass;
+
+ TypeInfo(Type actualType) {
+ this.actualType = actualType;
+ rawClass = TypeUtils.toRawClass(actualType);
+ }
+
+ public final Type getActualType() {
+ return actualType;
+ }
+
+ /**
+ * Returns the corresponding wrapper type of {@code type} if it is a primitive
+ * type; otherwise returns {@code type} itself. Idempotent.
+ *
+ * TypeUtils.getActualTypeForFirstTypeVariable(fooType) will return Integer.class.
+ */
+ static Type getActualTypeForFirstTypeVariable(Type type) {
+ if (type instanceof Class>) {
+ return Object.class;
+ } else if (type instanceof ParameterizedType) {
+ return ((ParameterizedType)type).getActualTypeArguments()[0];
+ } else if (type instanceof GenericArrayType) {
+ return getActualTypeForFirstTypeVariable(((GenericArrayType)type).getGenericComponentType());
+ } else {
+ throw new IllegalArgumentException("Type \'" + type + "\' is not a Class, "
+ + "ParameterizedType, or GenericArrayType. Can't extract class.");
+ }
+ }
+
+ static boolean isArray(Type type) {
+ if (type instanceof Class>) {
+ return ((Class>)type).isArray();
+ } else if (type instanceof GenericArrayType) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * This method returns the actual raw class associated with the specified type.
+ */
+ static Class> toRawClass(Type type) {
+ if (type instanceof Class>) {
+ return (Class>) type;
+ } else if (type instanceof ParameterizedType) {
+ ParameterizedType actualType = (ParameterizedType)type;
+ return toRawClass(actualType.getRawType());
+ } else if (type instanceof GenericArrayType) {
+ GenericArrayType actualType = (GenericArrayType) type;
+ Class> rawClass = toRawClass(actualType.getGenericComponentType());
+ return wrapWithArray(rawClass);
+ } else if (type instanceof WildcardType) {
+ WildcardType castedType = (WildcardType) type;
+ return toRawClass(castedType.getUpperBounds()[0]);
+ } else {
+ throw new IllegalArgumentException("Type \'" + type + "\' is not a Class, "
+ + "ParameterizedType, or GenericArrayType. Can't extract class.");
+ }
+ }
+
+ static Class> wrapWithArray(Class> rawClass) {
+ return Array.newInstance(rawClass, 0).getClass();
+ }
+
+ private TypeUtils() {
+ // Class with just some static utility methods, should not be instantiated
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/UpperCamelCaseSeparatorNamingPolicy.java b/src/org/mcteam/ancientgates/gson/UpperCamelCaseSeparatorNamingPolicy.java
new file mode 100644
index 0000000..ddc8cdd
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/UpperCamelCaseSeparatorNamingPolicy.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * A {@link FieldNamingStrategy2} that ensures the JSON field names consist of mixed
+ * case letters starting with a capital and are separated by a particular
+ * {@code separatorString}.
+ *
+ *
+ *
+ * @author Joel Leitch
+ */
+final class UpperCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
+
+ public UpperCamelCaseSeparatorNamingPolicy(String separatorString) {
+ super(new CamelCaseSeparatorNamingPolicy(separatorString),
+ new ModifyFirstLetterNamingPolicy(ModifyFirstLetterNamingPolicy.LetterModifier.UPPER));
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/UpperCaseNamingPolicy.java b/src/org/mcteam/ancientgates/gson/UpperCaseNamingPolicy.java
new file mode 100644
index 0000000..53efe3f
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/UpperCaseNamingPolicy.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ * A {@link FieldNamingStrategy2} that ensures the JSON field names consist of only
+ * upper case letters.
+ *
+ *
The following is an example:
+ *
+ * class IntWrapper {
+ * public int integerField = 0;
+ * }
+ *
+ * UpperCaseNamingPolicy policy = new UpperCaseNamingPolicy();
+ * String translatedFieldName =
+ * policy.translateName(IntWrapper.class.getField("integerField"));
+ *
+ * assert("INTEGERFIELD".equals(translatedFieldName));
+ *
+ *
+ * @author Joel Leitch
+ */
+final class UpperCaseNamingPolicy extends RecursiveFieldNamingPolicy {
+
+ @Override
+ protected String translateName(String target, Type fieldType, Collection annotations) {
+ return target.toUpperCase();
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/VersionConstants.java b/src/org/mcteam/ancientgates/gson/VersionConstants.java
new file mode 100644
index 0000000..f1f96b0
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/VersionConstants.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+/**
+ * Class contain all constants for versioning support.
+ *
+ * @author Joel Leitch
+ */
+final class VersionConstants {
+ // Prevent instantiation
+ private VersionConstants() { }
+
+ static final double IGNORE_VERSIONS = -1D;
+}
diff --git a/src/org/mcteam/ancientgates/gson/VersionExclusionStrategy.java b/src/org/mcteam/ancientgates/gson/VersionExclusionStrategy.java
new file mode 100644
index 0000000..6e48122
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/VersionExclusionStrategy.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson;
+
+import org.mcteam.ancientgates.gson.annotations.Since;
+import org.mcteam.ancientgates.gson.annotations.Until;
+
+/**
+ * This strategy will exclude any files and/or class that are passed the
+ * {@link #version} value.
+ *
+ * @author Joel Leitch
+ */
+final class VersionExclusionStrategy implements ExclusionStrategy {
+ private final double version;
+
+ public VersionExclusionStrategy(double version) {
+ Preconditions.checkArgument(version >= 0.0D);
+ this.version = version;
+ }
+
+ public boolean shouldSkipField(FieldAttributes f) {
+ return !isValidVersion(f.getAnnotation(Since.class), f.getAnnotation(Until.class));
+ }
+
+ public boolean shouldSkipClass(Class> clazz) {
+ return !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class));
+ }
+
+ private boolean isValidVersion(Since since, Until until) {
+ return (isValidSince(since) && isValidUntil(until));
+ }
+
+ private boolean isValidSince(Since annotation) {
+ if (annotation != null) {
+ double annotationVersion = annotation.value();
+ if (annotationVersion > version) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean isValidUntil(Until annotation) {
+ if (annotation != null) {
+ double annotationVersion = annotation.value();
+ if (annotationVersion <= version) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/annotations/Expose.java b/src/org/mcteam/ancientgates/gson/annotations/Expose.java
new file mode 100644
index 0000000..e6889f6
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/annotations/Expose.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation that indicates this member should be exposed for JSON
+ * serialization or deserialization.
+ *
+ *
This annotation has no effect unless you build {@link org.mcteam.ancientgates.gson.Gson}
+ * with a {@link org.mcteam.ancientgates.gson.GsonBuilder} and invoke
+ * {@link org.mcteam.ancientgates.gson.GsonBuilder#excludeFieldsWithoutExposeAnnotation()}
+ * method.
+ *
+ *
Here is an example of how this annotation is meant to be used:
+ *
+ * If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
+ * methods will use the {@code password} field along-with {@code firstName}, {@code lastName},
+ * and {@code emailAddress} for serialization and deserialization. However, if you created Gson
+ * with {@code Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()}
+ * then the {@code toJson()} and {@code fromJson()} methods of Gson will exclude the
+ * {@code password} field. This is because the {@code password} field is not marked with the
+ * {@code @Expose} annotation. Gson will also exclude {@code lastName} and {@code emailAddress}
+ * from serialization since {@code serialize} is set to {@code false}. Similarly, Gson will
+ * exclude {@code emailAddress} from deserialization since {@code deserialize} is set to false.
+ *
+ *
Note that another way to achieve the same effect would have been to just mark the
+ * {@code password} field as {@code transient}, and Gson would have excluded it even with default
+ * settings. The {@code @Expose} annotation is useful in a style of programming where you want to
+ * explicitly specify all fields that should get considered for serialization or deserialization.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Expose {
+
+ /**
+ * If {@code true}, the field marked with this annotation is written out in the JSON while
+ * serializing. If {@code false}, the field marked with this annotation is skipped from the
+ * serialized output. Defaults to {@code true}.
+ * @since 1.4
+ */
+ public boolean serialize() default true;
+
+ /**
+ * If {@code true}, the field marked with this annotation is deserialized from the JSON.
+ * If {@code false}, the field marked with this annotation is skipped during deserialization.
+ * Defaults to {@code true}.
+ * @since 1.4
+ */
+ public boolean deserialize() default true;
+}
diff --git a/src/org/mcteam/ancientgates/gson/annotations/SerializedName.java b/src/org/mcteam/ancientgates/gson/annotations/SerializedName.java
new file mode 100644
index 0000000..d7c3881
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/annotations/SerializedName.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation that indicates this member should be serialized to JSON with
+ * the provided name value as its field name.
+ *
+ *
This annotation will override any {@link org.mcteam.ancientgates.gson.FieldNamingPolicy}, including
+ * the default field naming policy, that may have been set on the {@link org.mcteam.ancientgates.gson.Gson}
+ * instance. A different naming policy can set using the {@code GsonBuilder} class. See
+ * {@link org.mcteam.ancientgates.gson.GsonBuilder#setFieldNamingPolicy(org.mcteam.ancientgates.gson.FieldNamingPolicy)}
+ * for more information.
+ *
+ *
Here is an example of how this annotation is meant to be used:
+ *
+ * public class SomeClassWithFields {
+ * @SerializedName("name") private final String someField;
+ * private final String someOtherField;
+ *
+ * public SomeClassWithFields(String a, String b) {
+ * this.someField = a;
+ * this.someOtherField = b;
+ * }
+ * }
+ *
+ *
+ *
The following shows the output that is generated when serializing an instance of the
+ * above example class:
NOTE: The value you specify in this annotation must be a valid JSON field name.
+ *
+ * @see org.mcteam.ancientgates.gson.FieldNamingPolicy
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface SerializedName {
+
+ /**
+ * @return the desired name of the field when it is serialized
+ */
+ String value();
+}
diff --git a/src/org/mcteam/ancientgates/gson/annotations/Since.java b/src/org/mcteam/ancientgates/gson/annotations/Since.java
new file mode 100644
index 0000000..abeb317
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/annotations/Since.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation that indicates the version number since a member or a type has been present.
+ * This annotation is useful to manage versioning of your Json classes for a web-service.
+ *
+ *
+ * This annotation has no effect unless you build {@link org.mcteam.ancientgates.gson.Gson} with a
+ * {@link org.mcteam.ancientgates.gson.GsonBuilder} and invoke
+ * {@link org.mcteam.ancientgates.gson.GsonBuilder#setVersion(double)} method.
+ *
+ *
Here is an example of how this annotation is meant to be used:
If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
+ * methods will use all the fields for serialization and deserialization. However, if you created
+ * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.0).create()} then the
+ * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code address} field
+ * since it's version number is set to {@code 1.1}.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.TYPE})
+public @interface Since {
+ /**
+ * the value indicating a version number since this member
+ * or type has been present.
+ */
+ double value();
+}
diff --git a/src/org/mcteam/ancientgates/gson/annotations/Until.java b/src/org/mcteam/ancientgates/gson/annotations/Until.java
new file mode 100644
index 0000000..36c1db0
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/annotations/Until.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation that indicates the version number until a member or a type should be present.
+ * Basically, if Gson is created with a version number that exceeds the value stored in the
+ * {@code Until} annotation then the field will be ignored from the JSON output. This annotation
+ * is useful to manage versioning of your JSON classes for a web-service.
+ *
+ *
+ * This annotation has no effect unless you build {@link org.mcteam.ancientgates.gson.Gson} with a
+ * {@link org.mcteam.ancientgates.gson.GsonBuilder} and invoke
+ * {@link org.mcteam.ancientgates.gson.GsonBuilder#setVersion(double)} method.
+ *
+ *
Here is an example of how this annotation is meant to be used:
If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
+ * methods will use all the fields for serialization and deserialization. However, if you created
+ * Gson with {@code Gson gson = new GsonBuilder().setVersion(1.2).create()} then the
+ * {@code toJson()} and {@code fromJson()} methods of Gson will exclude the {@code emailAddress}
+ * and {@code password} fields from the example above, because the version number passed to the
+ * GsonBuilder, {@code 1.2}, exceeds the version number set on the {@code Until} annotation,
+ * {@code 1.1}, for those fields.
+ *
+ * @author Inderjeet Singh
+ * @author Joel Leitch
+ * @since 1.3
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.TYPE})
+public @interface Until {
+
+ /**
+ * the value indicating a version number until this member
+ * or type should be ignored.
+ */
+ double value();
+}
diff --git a/src/org/mcteam/ancientgates/gson/annotations/package-info.java b/src/org/mcteam/ancientgates/gson/annotations/package-info.java
new file mode 100644
index 0000000..0d6165d
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/annotations/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package provides annotations that can be used with {@link org.mcteam.ancientgates.gson.Gson}.
+ *
+ * @author Inderjeet Singh, Joel Leitch
+ */
+package org.mcteam.ancientgates.gson.annotations;
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/package-info.java b/src/org/mcteam/ancientgates/gson/package-info.java
new file mode 100644
index 0000000..84f87fa
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/package-info.java
@@ -0,0 +1,11 @@
+/**
+ * This package provides the {@link com.bukkit.mcteam.gson.Gson} class to convert Json to Java and
+ * vice-versa.
+ *
+ *
The primary class to use is {@link com.bukkit.mcteam.gson.Gson} which can be constructed with
+ * {@code new Gson()} (using default settings) or by using {@link com.bukkit.mcteam.gson.GsonBuilder}
+ * (to configure various options such as using versioning and so on).
+ *
+ * @author Inderjeet Singh, Joel Leitch
+ */
+package org.mcteam.ancientgates.gson;
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/reflect/TypeToken.java b/src/org/mcteam/ancientgates/gson/reflect/TypeToken.java
new file mode 100644
index 0000000..8f890f7
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/reflect/TypeToken.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson.reflect;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a generic type {@code T}.
+ *
+ * You can use this class to get the generic type for a class. For example,
+ * to get the generic type for Collection<Foo>, you can use:
+ *
+ * Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
+ *
+ *
+ *
Assumes {@code Type} implements {@code equals()} and {@code hashCode()}
+ * as a value (as opposed to identity) comparison.
+ *
+ * Also implements {@link #isAssignableFrom(Type)} to check type-safe
+ * assignability.
+ *
+ * @author Bob Lee
+ * @author Sven Mawson
+ */
+public abstract class TypeToken {
+
+ final Class super T> rawType;
+ final Type type;
+
+ /**
+ * Constructs a new type token. Derives represented class from type
+ * parameter.
+ *
+ *
Clients create an empty anonymous subclass. Doing so embeds the type
+ * parameter in the anonymous class's type hierarchy so we can reconstitute
+ * it at runtime despite erasure.
+ *
+ *
For example:
+ *
+ * {@literal TypeToken> t = new TypeToken>}(){}
+ *
+ */
+ @SuppressWarnings("unchecked")
+ protected TypeToken() {
+ this.type = getSuperclassTypeParameter(getClass());
+ this.rawType = (Class super T>) getRawType(type);
+ }
+
+ /**
+ * Unsafe. Constructs a type token manually.
+ */
+ @SuppressWarnings({"unchecked"})
+ private TypeToken(Type type) {
+ this.rawType = (Class super T>) getRawType(nonNull(type, "type"));
+ this.type = type;
+ }
+
+ private static T nonNull(T o, String message) {
+ if (o == null) {
+ throw new NullPointerException(message);
+ }
+ return o;
+ }
+
+ /**
+ * Gets type from super class's type parameter.
+ */
+ static Type getSuperclassTypeParameter(Class> subclass) {
+ Type superclass = subclass.getGenericSuperclass();
+ if (superclass instanceof Class>) {
+ throw new RuntimeException("Missing type parameter.");
+ }
+ return ((ParameterizedType) superclass).getActualTypeArguments()[0];
+ }
+
+ /**
+ * Gets type token from super class's type parameter.
+ */
+ static TypeToken> fromSuperclassTypeParameter(Class> subclass) {
+ return new SimpleTypeToken(subclass);
+ }
+
+ private static Class> getRawType(Type type) {
+ if (type instanceof Class>) {
+ // type is a normal class.
+ return (Class>) type;
+ } else if (type instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+
+ // I'm not exactly sure why getRawType() returns Type instead of Class.
+ // Neal isn't either but suspects some pathological case related
+ // to nested classes exists.
+ Type rawType = parameterizedType.getRawType();
+ if (rawType instanceof Class>) {
+ return (Class>) rawType;
+ }
+ throw buildUnexpectedTypeError(rawType, Class.class);
+ } else if (type instanceof GenericArrayType) {
+ GenericArrayType genericArrayType = (GenericArrayType) type;
+
+ // TODO(jleitch): This is not the most efficient way to handle generic
+ // arrays, but is there another way to extract the array class in a
+ // non-hacky way (i.e. using String value class names- "[L...")?
+ Object rawArrayType = Array.newInstance(
+ getRawType(genericArrayType.getGenericComponentType()), 0);
+ return rawArrayType.getClass();
+ } else {
+ throw buildUnexpectedTypeError(
+ type, ParameterizedType.class, GenericArrayType.class);
+ }
+ }
+
+ /**
+ * Gets the raw type.
+ */
+ public Class super T> getRawType() {
+ return rawType;
+ }
+
+ /**
+ * Gets underlying {@code Type} instance.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Check if this type is assignable from the given class object.
+ */
+ public boolean isAssignableFrom(Class> cls) {
+ return isAssignableFrom((Type) cls);
+ }
+
+ /**
+ * Check if this type is assignable from the given Type.
+ */
+ public boolean isAssignableFrom(Type from) {
+ if (from == null) {
+ return false;
+ }
+
+ if (type.equals(from)) {
+ return true;
+ }
+
+ if (type instanceof Class>) {
+ return rawType.isAssignableFrom(getRawType(from));
+ } else if (type instanceof ParameterizedType) {
+ return isAssignableFrom(from, (ParameterizedType) type,
+ new HashMap());
+ } else if (type instanceof GenericArrayType) {
+ return rawType.isAssignableFrom(getRawType(from))
+ && isAssignableFrom(from, (GenericArrayType) type);
+ } else {
+ throw buildUnexpectedTypeError(
+ type, Class.class, ParameterizedType.class, GenericArrayType.class);
+ }
+ }
+
+ /**
+ * Check if this type is assignable from the given type token.
+ */
+ public boolean isAssignableFrom(TypeToken> token) {
+ return isAssignableFrom(token.getType());
+ }
+
+ /**
+ * Private helper function that performs some assignability checks for
+ * the provided GenericArrayType.
+ */
+ private static boolean isAssignableFrom(Type from, GenericArrayType to) {
+ Type toGenericComponentType = to.getGenericComponentType();
+ if (toGenericComponentType instanceof ParameterizedType) {
+ Type t = from;
+ if (from instanceof GenericArrayType) {
+ t = ((GenericArrayType) from).getGenericComponentType();
+ } else if (from instanceof Class>) {
+ Class> classType = (Class>) from;
+ while (classType.isArray()) {
+ classType = classType.getComponentType();
+ }
+ t = classType;
+ }
+ return isAssignableFrom(t, (ParameterizedType) toGenericComponentType,
+ new HashMap());
+ }
+ // No generic defined on "to"; therefore, return true and let other
+ // checks determine assignability
+ return true;
+ }
+
+ /**
+ * Private recursive helper function to actually do the type-safe checking
+ * of assignability.
+ */
+ private static boolean isAssignableFrom(Type from, ParameterizedType to,
+ Map typeVarMap) {
+
+ if (from == null) {
+ return false;
+ }
+
+ if (to.equals(from)) {
+ return true;
+ }
+
+ // First figure out the class and any type information.
+ Class> clazz = getRawType(from);
+ ParameterizedType ptype = null;
+ if (from instanceof ParameterizedType) {
+ ptype = (ParameterizedType) from;
+ }
+
+ // Load up parameterized variable info if it was parameterized.
+ if (ptype != null) {
+ Type[] tArgs = ptype.getActualTypeArguments();
+ TypeVariable>[] tParams = clazz.getTypeParameters();
+ for (int i = 0; i < tArgs.length; i++) {
+ Type arg = tArgs[i];
+ TypeVariable> var = tParams[i];
+ while (arg instanceof TypeVariable>) {
+ TypeVariable> v = (TypeVariable>) arg;
+ arg = typeVarMap.get(v.getName());
+ }
+ typeVarMap.put(var.getName(), arg);
+ }
+
+ // check if they are equivalent under our current mapping.
+ if (typeEquals(ptype, to, typeVarMap)) {
+ return true;
+ }
+ }
+
+ for (Type itype : clazz.getGenericInterfaces()) {
+ if (isAssignableFrom(itype, to, new HashMap(typeVarMap))) {
+ return true;
+ }
+ }
+
+ // Interfaces didn't work, try the superclass.
+ Type sType = clazz.getGenericSuperclass();
+ if (isAssignableFrom(sType, to, new HashMap(typeVarMap))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if two parameterized types are exactly equal, under the variable
+ * replacement described in the typeVarMap.
+ */
+ private static boolean typeEquals(ParameterizedType from,
+ ParameterizedType to, Map typeVarMap) {
+ if (from.getRawType().equals(to.getRawType())) {
+ Type[] fromArgs = from.getActualTypeArguments();
+ Type[] toArgs = to.getActualTypeArguments();
+ for (int i = 0; i < fromArgs.length; i++) {
+ if (!matches(fromArgs[i], toArgs[i], typeVarMap)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if two types are the same or are equivalent under a variable mapping
+ * given in the type map that was provided.
+ */
+ private static boolean matches(Type from, Type to,
+ Map typeMap) {
+ if (to.equals(from)) return true;
+
+ if (from instanceof TypeVariable>) {
+ return to.equals(typeMap.get(((TypeVariable>)from).getName()));
+ }
+
+ return false;
+ }
+
+ /**
+ * Hashcode for this object.
+ * @return hashcode for this object.
+ */
+ @Override public int hashCode() {
+ return type.hashCode();
+ }
+
+ /**
+ * Method to test equality.
+ *
+ * @return true if this object is logically equal to the specified object, false otherwise.
+ */
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof TypeToken>)) {
+ return false;
+ }
+ TypeToken> t = (TypeToken>) o;
+ return type.equals(t.type);
+ }
+
+ /**
+ * Returns a string representation of this object.
+ * @return a string representation of this object.
+ */
+ @Override public String toString() {
+ return type instanceof Class>
+ ? ((Class>) type).getName()
+ : type.toString();
+ }
+
+ private static AssertionError buildUnexpectedTypeError(
+ Type token, Class>... expected) {
+
+ // Build exception message
+ StringBuilder exceptionMessage =
+ new StringBuilder("Unexpected type. Expected one of: ");
+ for (Class> clazz : expected) {
+ exceptionMessage.append(clazz.getName()).append(", ");
+ }
+ exceptionMessage.append("but got: ").append(token.getClass().getName())
+ .append(", for type token: ").append(token.toString()).append('.');
+
+ return new AssertionError(exceptionMessage.toString());
+ }
+
+ /**
+ * Gets type token for the given {@code Type} instance.
+ */
+ public static TypeToken> get(Type type) {
+ return new SimpleTypeToken(type);
+ }
+
+ /**
+ * Gets type token for the given {@code Class} instance.
+ */
+ public static TypeToken get(Class type) {
+ return new SimpleTypeToken(type);
+ }
+
+ /**
+ * Private static class to not create more anonymous classes than
+ * necessary.
+ */
+ private static class SimpleTypeToken extends TypeToken {
+ public SimpleTypeToken(Type type) {
+ super(type);
+ }
+ }
+}
diff --git a/src/org/mcteam/ancientgates/gson/reflect/package-info.java b/src/org/mcteam/ancientgates/gson/reflect/package-info.java
new file mode 100644
index 0000000..c4c5752
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/reflect/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package provides utility classes for finding type information for generic types.
+ *
+ * @author Inderjeet Singh, Joel Leitch
+ */
+package org.mcteam.ancientgates.gson.reflect;
\ No newline at end of file
diff --git a/src/org/mcteam/ancientgates/gson/stream/JsonReader.java b/src/org/mcteam/ancientgates/gson/stream/JsonReader.java
new file mode 100644
index 0000000..e276efc
--- /dev/null
+++ b/src/org/mcteam/ancientgates/gson/stream/JsonReader.java
@@ -0,0 +1,1121 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mcteam.ancientgates.gson.stream;
+
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Reads a JSON (RFC 4627)
+ * encoded value as a stream of tokens. This stream includes both literal
+ * values (strings, numbers, booleans, and nulls) as well as the begin and
+ * end delimiters of objects and arrays. The tokens are traversed in
+ * depth-first order, the same order that they appear in the JSON document.
+ * Within JSON objects, name/value pairs are represented by a single token.
+ *
+ *
Parsing JSON
+ * To create a recursive descent parser your own JSON streams, first create an
+ * entry point method that creates a {@code JsonReader}.
+ *
+ *
Next, create handler methods for each structure in your JSON text. You'll
+ * need a method for each object type and for each array type.
+ *
+ *
Within array handling methods, first call {@link
+ * #beginArray} to consume the array's opening bracket. Then create a
+ * while loop that accumulates values, terminating when {@link #hasNext}
+ * is false. Finally, read the array's closing bracket by calling {@link
+ * #endArray}.
+ *
Within object handling methods, first call {@link
+ * #beginObject} to consume the object's opening brace. Then create a
+ * while loop that assigns values to local variables based on their name.
+ * This loop should terminate when {@link #hasNext} is false. Finally,
+ * read the object's closing brace by calling {@link #endObject}.
+ *
+ *
When a nested object or array is encountered, delegate to the
+ * corresponding handler method.
+ *
+ *
When an unknown name is encountered, strict parsers should fail with an
+ * exception. Lenient parsers should call {@link #skipValue()} to recursively
+ * skip the value's nested tokens, which may otherwise conflict.
+ *
+ *
If a value may be null, you should first check using {@link #peek()}.
+ * Null literals can be consumed using either {@link #nextNull()} or {@link
+ * #skipValue()}.
+ *
+ *
Example
+ * Suppose we'd like to parse a stream of messages such as the following:
+ * This code implements the parser for the above structure:
{@code
+ *
+ * public List readJsonStream(InputStream in) throws IOException {
+ * JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
+ * return readMessagesArray(reader);
+ * }
+ *
+ * public List readMessagesArray(JsonReader reader) throws IOException {
+ * List messages = new ArrayList();
+ *
+ * reader.beginArray();
+ * while (reader.hasNext()) {
+ * messages.add(readMessage(reader));
+ * }
+ * reader.endArray();
+ * return messages;
+ * }
+ *
+ * public Message readMessage(JsonReader reader) throws IOException {
+ * long id = -1;
+ * String text = null;
+ * User user = null;
+ * List geo = null;
+ *
+ * reader.beginObject();
+ * while (reader.hasNext()) {
+ * String name = reader.nextName();
+ * if (name.equals("id")) {
+ * id = reader.nextLong();
+ * } else if (name.equals("text")) {
+ * text = reader.nextString();
+ * } else if (name.equals("geo") && reader.peek() != JsonToken.NULL) {
+ * geo = readDoublesArray(reader);
+ * } else if (name.equals("user")) {
+ * user = readUser(reader);
+ * } else {
+ * reader.skipValue();
+ * }
+ * }
+ * reader.endObject();
+ * return new Message(id, text, user, geo);
+ * }
+ *
+ * public List readDoublesArray(JsonReader reader) throws IOException {
+ * List doubles = new ArrayList();
+ *
+ * reader.beginArray();
+ * while (reader.hasNext()) {
+ * doubles.add(reader.nextDouble());
+ * }
+ * reader.endArray();
+ * return doubles;
+ * }
+ *
+ * public User readUser(JsonReader reader) throws IOException {
+ * String username = null;
+ * int followersCount = -1;
+ *
+ * reader.beginObject();
+ * while (reader.hasNext()) {
+ * String name = reader.nextName();
+ * if (name.equals("name")) {
+ * username = reader.nextString();
+ * } else if (name.equals("followers_count")) {
+ * followersCount = reader.nextInt();
+ * } else {
+ * reader.skipValue();
+ * }
+ * }
+ * reader.endObject();
+ * return new User(username, followersCount);
+ * }}
+ *
+ *
Number Handling
+ * This reader permits numeric values to be read as strings and string values to
+ * be read as numbers. For example, both elements of the JSON array {@code
+ * [1, "1"]} may be read using either {@link #nextInt} or {@link #nextString}.
+ * This behavior is intended to prevent lossy numeric conversions: double is
+ * JavaScript's only numeric type and very large values like {@code
+ * 9007199254740993} cannot be represented exactly on that platform. To minimize
+ * precision loss, extremely large values should be written and read as strings
+ * in JSON.
+ *
+ *
Non-Execute Prefix
+ * Web servers that serve private data using JSON may be vulnerable to Cross-site
+ * request forgery attacks. In such an attack, a malicious site gains access
+ * to a private JSON file by executing it with an HTML {@code