Compare commits
323 Commits
bukkit1.2
...
development
| Author | SHA1 | Date | |
|---|---|---|---|
| d5d079bfcf | |||
| 3b16a6372b | |||
| f20882e03a | |||
| c04aac10f6 | |||
| a38e12fbe6 | |||
| 8a199b4074 | |||
| ed5222e5fb | |||
| 1177d6e537 | |||
| 465533f4fe | |||
| 4c7f1201bd | |||
| 64a7ac50fa | |||
| aaf0002105 | |||
| e34276b729 | |||
| ed32b23823 | |||
| 790fd5bccd | |||
| acd96607d4 | |||
| 96d9316b11 | |||
| 892f151e38 | |||
| 3bc5ba500c | |||
| 927b70fd2d | |||
| 344e69cefd | |||
| 40b396f8a2 | |||
| efb4b14b79 | |||
| 238dbe3e51 | |||
| 4deb8a3c6d | |||
| e2903514fe | |||
| 44e86059de | |||
| fe0946117e | |||
| 43dd934f48 | |||
| b37f1000ab | |||
| c7a423ff20 | |||
| b676af278d | |||
| a579209037 | |||
| ca74b2e3ed | |||
| 6924e36249 | |||
| f8f31640ef | |||
| c80b0f0f68 | |||
| 2bd8b0ff03 | |||
| a613b1933a | |||
| d8fff26c9e | |||
| 0c13d0d3e3 | |||
| 29592823b6 | |||
| 56c6af02b1 | |||
| 8b873a6d60 | |||
| e36519c246 | |||
| 125d327a0d | |||
| 6c8658f7c5 | |||
| 14041f8cd7 | |||
| bb4a41e782 | |||
| 82df684c22 | |||
| 7f89917e81 | |||
| a1cb0102f8 | |||
| 5af520f8ea | |||
| 28cacfdb19 | |||
| 757d6b5a48 | |||
| 056b8896a6 | |||
| 12a0bba6cc | |||
| e9a454182a | |||
| 260cabc509 | |||
| 0b29936958 | |||
| efc30d0ae0 | |||
| f4111fb34f | |||
| 37bce23e3d | |||
| d5ff63c163 | |||
| e60c735153 | |||
| 013fad2b95 | |||
| 5ace80e6d1 | |||
| 42b293e6bc | |||
| 54545a9ee1 | |||
| 560bbf0394 | |||
| 2150cc66d0 | |||
| 7673c3f674 | |||
| 577531db5e | |||
| 3739ee6c5a | |||
| 2d830b2f9f | |||
| 02fd7a4916 | |||
| e21089d8c7 | |||
| fc488e7f31 | |||
| e8f23078f1 | |||
| 9ec2b91181 | |||
| 478095190a | |||
| 17942caa73 | |||
| d0c23b581a | |||
| 6884f43e50 | |||
| e84130a8fe | |||
| 8f54c0acc2 | |||
| aeae14e2a0 | |||
| 36be95d0f5 | |||
| ed4dd5711e | |||
| 437296262c | |||
| ec2caaad97 | |||
| 81daa83f44 | |||
| 0695b3e202 | |||
| 6df27c14a0 | |||
| a16d847234 | |||
| d24f0b8fd1 | |||
| ea52e4d87e | |||
| f4495240a5 | |||
| 09b9c65ef6 | |||
| afe693d491 | |||
| d4f33a1885 | |||
| b50a2b27d3 | |||
| e88e03ed42 | |||
| 53e2be6be7 | |||
| d29ad9a474 | |||
| 4f89e20e6f | |||
| 563bdfe2fd | |||
| 931cd1a520 | |||
| b64f41ce0c | |||
| 1e9b9905a5 | |||
| d28bedb78e | |||
| e9c4583c3d | |||
| 7a8e61104a | |||
| c764850ded | |||
| f939e27464 | |||
| ecd219fb2d | |||
| 99be2905be | |||
| 9e36cf189b | |||
| 78283a4f34 | |||
| 1d08c79cff | |||
| cb0dec8b83 | |||
| 1968ccaaeb | |||
| d23a9b7650 | |||
| e5ef266f04 | |||
| 724e05e0a4 | |||
| b18df58870 | |||
| 7119c185e7 | |||
| c740a5b111 | |||
| 8bee74df89 | |||
| b383ff89c6 | |||
| fec999541e | |||
| 2ed611d995 | |||
| faabb2f9db | |||
| e6e6273147 | |||
| 093778f2fb | |||
| a5b34458c4 | |||
| 30d15c141e | |||
| 3cac4e70cc | |||
| 95446f1371 | |||
| 8e860e90c6 | |||
| d9194c7497 | |||
| c3a24a940f | |||
| c62fb32e90 | |||
| 580fda0273 | |||
| 252292819f | |||
| 79dcd259dc | |||
| 12fde472a2 | |||
| be3c541845 | |||
| 6bd53a3fe6 | |||
| a9be1eaa51 | |||
| dd492a7327 | |||
| 0230314c7e | |||
| 768d385915 | |||
| 232305a871 | |||
| 00573c2763 | |||
| f1d623df60 | |||
| 040377cb36 | |||
| e9027900ce | |||
| 34b1c7e0ce | |||
| 987de39bf9 | |||
| 0e13f60122 | |||
| f2bfe27eba | |||
| 7f8b8eee0f | |||
| e0b30135cc | |||
| 1056fbf969 | |||
| 916dc1b3a1 | |||
| 4b7fff2277 | |||
| ed2683affc | |||
| cac6eb6022 | |||
| 67c8a15e46 | |||
| a984f3a3ea | |||
| f253dd4ccc | |||
| 71031d0578 | |||
| e30b82b74f | |||
| acf4c9002c | |||
| 4012a4ac15 | |||
| 8c6718d13f | |||
| 6a34d44f20 | |||
| b196c53335 | |||
| d54fd7f72e | |||
| cede47deab | |||
| 1ef178f6a0 | |||
| 802f8c07e3 | |||
| a8a95af497 | |||
| 0af3631693 | |||
| 4d40b140fa | |||
| 8830355216 | |||
| 3481c2a10f | |||
| a319f793b2 | |||
| 6373f98894 | |||
| e49c5c0acb | |||
| a0bc62f767 | |||
| 850fbf1515 | |||
| b99ecec448 | |||
| 3a7be837b5 | |||
| 1bfc886969 | |||
| 880071140a | |||
| 5b1ac6e8f7 | |||
| 08906f6004 | |||
| e54914bd22 | |||
| 606ea1d5c5 | |||
| b072229914 | |||
| 0b8be1ec4b | |||
| 1fef272af2 | |||
| 26927d35c2 | |||
| c79a856907 | |||
| c25bb01aa1 | |||
| 68bf008bc4 | |||
| 638afcc82f | |||
| f020096126 | |||
| a4ee78b88a | |||
| f3a87516d6 | |||
| 984069ff35 | |||
| 0dacfaa79b | |||
| 02262880da | |||
| 9ce65ed26d | |||
| db173521e4 | |||
| 16095226f9 | |||
| 3ea11da591 | |||
| 59fdb54a09 | |||
| 02b904a78d | |||
| 0117e7294a | |||
| 1de6812eb6 | |||
| 26e5b68a7d | |||
| f09b90f0a6 | |||
| 32f1cba2bd | |||
| 56a5f828ee | |||
| cd0ebc3a7a | |||
| dd5a60cb2a | |||
| 32fc475a8a | |||
| 43f002032d | |||
| cf2155ab40 | |||
| b9e84b122d | |||
| 749c04f585 | |||
| dae92a0357 | |||
| ca982f5ba9 | |||
| 5b4036ac7c | |||
| bf1f2bcff2 | |||
| ead21c0b79 | |||
| ed58f762fe | |||
| 59a7f4f80e | |||
| 58695cadd3 | |||
| cab78c34cc | |||
| e407d2b9fa | |||
| 936619a1b5 | |||
| 8e7b180fbe | |||
| 56d0b8bf1c | |||
| 0f6f05b045 | |||
| 13b97d2c78 | |||
| 304009d978 | |||
| e4662fbc0d | |||
| 776e4ef3c9 | |||
| a677995968 | |||
| 67fc0abe9b | |||
| 01348188d9 | |||
| 94619cb90f | |||
| e9ec81cf04 | |||
| 5ec8a05688 | |||
| 50dad81876 | |||
| 0cd67f3488 | |||
| ed9aa2fa09 | |||
| 384c2b819d | |||
| 7e4e911a68 | |||
| 6b28b4dc8a | |||
| e1dbb96ff4 | |||
| e7e8f6ab8c | |||
| bc92ce6707 | |||
| 9067f875ce | |||
| 139bfc7d54 | |||
| 9e3b6a6cdb | |||
| bbe4b29073 | |||
| 8375a390cc | |||
| 6e2fa9237a | |||
| 30d1ed1f9b | |||
| 09da38f354 | |||
| 7be2f02e03 | |||
| 107de7551c | |||
| 7f2c85e5cc | |||
| 1844df81f3 | |||
| 69571ea511 | |||
| 2ee725dc21 | |||
| aa520bb36e | |||
| afc7efcf26 | |||
| 649777c939 | |||
| c5490270de | |||
| d605e54a1c | |||
| f5049ecdfb | |||
| fc5752f840 | |||
| cd42698928 | |||
| 5f12bb5d99 | |||
| 94404d74c6 | |||
| 259d2cd3c4 | |||
| d293eaf52d | |||
| b43ffd17df | |||
| f7a86b3c6f | |||
| 3c5f37d170 | |||
| 297769181e | |||
| 0a1d744f0c | |||
| 181785c1b1 | |||
| 87e56742d4 | |||
| 81e59b1eed | |||
| 750a867d2f | |||
| 737ea7521e | |||
| a07df19c40 | |||
| 7e300d9c03 | |||
| 3d6b5fe1c6 | |||
| 13e4d3608c | |||
| df6a49ce2c | |||
| af24d7365a | |||
| 3e80f67770 | |||
| 387ee10069 | |||
| ae60da9e29 | |||
| 52a9278dfc | |||
| d4123d137a | |||
| 4b5e4a5e13 | |||
| 448763171d | |||
| a4925350e3 | |||
| 33c03d68c1 | |||
| 3fc35e13bc | |||
| 8e816bb5d2 | |||
| 21b9d8d530 | |||
| 1ad4b86587 | |||
| 4db38606f2 |
+3
-6
@@ -1,11 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
<classpathentry kind="lib" path="/Users/tobi/Code/Vault.jar"/>
|
||||||
<classpathentry kind="lib" path="/Volumes/Data HD/Users/tobi/Code/bukkit-1.1-R5-20120224.051137-12.jar" sourcepath="/Users/tobi/Desktop/Bukkit">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
<attributes>
|
<classpathentry kind="lib" path="/Users/tobi/Code/craftbukkit-1.5.1-R0.1.jar"/>
|
||||||
<attribute name="javadoc_location" value="http://jd.bukkit.org/apidocs/"/>
|
|
||||||
</attributes>
|
|
||||||
</classpathentry>
|
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
+12
-1
@@ -6,6 +6,13 @@
|
|||||||
# netbeans
|
# netbeans
|
||||||
/nbproject
|
/nbproject
|
||||||
|
|
||||||
|
# intelliJ
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# maven
|
||||||
|
target/
|
||||||
|
|
||||||
# vim
|
# vim
|
||||||
.*.sw[a-p]
|
.*.sw[a-p]
|
||||||
|
|
||||||
@@ -20,4 +27,8 @@
|
|||||||
profile
|
profile
|
||||||
|
|
||||||
# bukkit
|
# bukkit
|
||||||
bukkit/
|
bukkit/
|
||||||
|
|
||||||
|
# bukkit test-server
|
||||||
|
bukkit-testserver/
|
||||||
|
dependency-reduced-pom.xml
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<projectDescription>
|
<projectDescription>
|
||||||
<name>AncientGates</name>
|
<name>craftinc-gates</name>
|
||||||
<comment></comment>
|
<comment></comment>
|
||||||
<projects>
|
<projects>
|
||||||
</projects>
|
</projects>
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#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
|
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
The following persons contributed to Craft Inc. Gates (previously named Ancient Gates):
|
||||||
|
|
||||||
|
CURRENT MAINTAINERS
|
||||||
|
|
||||||
|
Tobias Ottenweller <mail@ottenweller.net>
|
||||||
|
Paul Schulze <info@paul-schulze.de>
|
||||||
|
|
||||||
|
|
||||||
|
FORMER CONTRIBUTORS (alphabetical order)
|
||||||
|
|
||||||
|
Jacob Brunson <jacob@dimensionsmachine.com>
|
||||||
|
locutus <bladedpenguin@gmail.com>
|
||||||
|
Olof Larsson <olof@sylt.nu>
|
||||||
-674
@@ -1,674 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
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.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
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
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
||||||
@@ -1,50 +1,85 @@
|
|||||||
#AncientGates - Easily create portals with custom design#
|
# Craft Inc. Gates #
|
||||||
|
|
||||||
Read the full userguide here: TODO
|
This awesome plugin lets you _travel_ to far away places and worlds _faster than light_! Just create a gate at any location and set an exit somewhere else.
|
||||||
|
|
||||||
With this plugin the server operators (OPs) can create gates that will teleport anyone who enter to a location specific to that gate. The hightlights are: __It is so darn easy to use!__ :D and __The gates can look any way you like__ \o/
|
This has been made available by the hard work of the research and development department of the _Craft Inc. Corporation_. Under the lead of Professor Ddidderr Craftman scientists worked years to find a way to bend time and space inside the Minecraft universe to enable _ultra fast transportation_.
|
||||||
|
|
||||||
Try the ingame command: __/gate__
|
Now it is time for _you_ to try out this wonderful plugin. Simply install, create a gate and feel the funny tickle inside your brain while traveling.*
|
||||||
Thought first you should take a look at the demonstration oloflarsson and karibu6 created:
|
|
||||||
__[http://www.youtube.com/watch?v=L4hyqTpeEaA](http://www.youtube.com/watch?v=L4hyqTpeEaA)__
|
|
||||||
|
|
||||||
##Commands##
|
The key features of this are:
|
||||||
|
|
||||||
* __/gate help,h,? *[page]__ Display a help page
|
* Dynmap integration
|
||||||
* __/gate create,new [id]__ Create a gate
|
* Gates with and without frames
|
||||||
* __/gate createsetfrom,newsetfrom,csf,nsf [id]__ Create a gate and set "from"
|
* Gates consisting of portal blocks and gates made of air (so called hidden gates)
|
||||||
* __/gate delete,del,remove,rm [id]__ Delete a gate
|
* Gates with destinations in different worlds
|
||||||
* __/gate setfrom [id]__ Set "from" to your location.
|
* Gates with custom shapes (gates can look any way you want)
|
||||||
* __/gate setto [id]__ Set "to" to your location.
|
* Riding through gates
|
||||||
* __/gate open [id]__ Open that gate
|
|
||||||
* __/gate close [id]__ Close that gate
|
|
||||||
* __/gate list,ls [page]__ Display a list of the gates
|
|
||||||
* __/gate info,details [id]__ Display information about a gate
|
|
||||||
|
|
||||||
##FAQ##
|
|
||||||
|
|
||||||
__Why the name AncientGates?__
|
*The Craft Inc. Corporation won't take any responsibility for seasickness, memory loss and sudden suffocation in walls while traveling with one of our gates!
|
||||||
|
|
||||||
Because the purpose of this plugin that I envision is that players should not be able to create gates to other worlds themselves. The server operators build gates with cool ruins around them and in order to get to another world the players need to find one of those ruins.
|
## FAQ ##
|
||||||
|
|
||||||
__Who can create a gate?__
|
__Who can create a gate?__
|
||||||
|
|
||||||
Only server operators! Not normal players. There is no suport for any permissions plugin.
|
Have a look at the [_Permissions_](http://dev.bukkit.org/bukkit-plugins/craftinc-gates/pages/permissions/) page.
|
||||||
|
|
||||||
__Who can destroy a gate?__
|
__Who can destroy a gate?__
|
||||||
|
|
||||||
Anyone if you do not use a third-party protection plugin like Factions.
|
Anyone if you do not use a third-party protection plugin like Grief Prevention.
|
||||||
|
|
||||||
__Are there IConnomy integration, Features for user to dial other gates etc?__
|
__Is there a IConnomy integration? Features for user to dial other gates etc?__
|
||||||
|
|
||||||
Nope. This plugin is very minimalistic and plain. Server operators manage the portals players use them any time they are open.
|
Nope. We currently don't plan to integrate such features. If you really need such an integration please inform us. If there are a lot of people requesting such features we might change our mind.
|
||||||
|
|
||||||
Installing
|
__Is there a list of all commands?__
|
||||||
----------
|
|
||||||
1. Download the latest release: __[https://github.com/tomco/minecraft-ancient-gates/downloads](https://github.com/tomco/minecraft-ancient-gates/downloads)__
|
|
||||||
1. Put AncientGates.jar in the plugins folder.
|
|
||||||
|
|
||||||
License
|
Sure, type _/gate help_ in-game or have a look at the [_Commands_](http://dev.bukkit.org/bukkit-plugins/craftinc-gates/pages/commands/) page.
|
||||||
----------
|
|
||||||
This project has a LGPL license just like the Bukkit project.<br>
|
__When I destroy the frame of a gate it stops working. Shouldn't it still work?__
|
||||||
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 ).
|
|
||||||
|
Yes and no. To make gates work without a frame you need to tweak the _checkForBrokenGateFrames_ setting. Have a look at the [_Configuration_](http://dev.bukkit.org/bukkit-plugins/craftinc-gates/pages/configuration/) page for more information.
|
||||||
|
|
||||||
|
|
||||||
|
## Usage ##
|
||||||
|
With this plugin you can create gates which will teleport players anywhere you want. The gates can look any way you like.
|
||||||
|
|
||||||
|
To make the gate work place yourself inside a newly created gate frame and type __/gate new [id]__. Afterwards walk to the destination of your gate and type __/gate exit [id]__ to set the destination. With __/gate open [id]__ you can get your newly created gate to work.
|
||||||
|
|
||||||
|
To hide a gate simply call __/gate hide [id]__. Now that gate won’t be made of purple portal blocks while open.
|
||||||
|
|
||||||
|
Have a look at the [_Commands_](http://dev.bukkit.org/bukkit-plugins/craftinc-gates/pages/commands/) page to find out how to modify gates even further.
|
||||||
|
|
||||||
|
|
||||||
|
## Installing ##
|
||||||
|
|
||||||
|
1. Download the latest release _[here](http://dev.bukkit.org/bukkit-plugins/craftinc-gates/files/)_
|
||||||
|
2. Delete any old versions of _Craft Inc. Gates_ (only the .jar files) including the extra dynmap-plugin of this plugin.
|
||||||
|
3. Extract the content of the zip file into the plugins folder of your Bukkit server.
|
||||||
|
4. Start or reload the server.
|
||||||
|
|
||||||
|
## Craft Inc. ##
|
||||||
|
Check out our __[Craft Inc. Minecraft Server](http://www.craftinc.de)__. Everyone is welcome!
|
||||||
|
|
||||||
|
Also check out our other great plugins:
|
||||||
|
|
||||||
|
* [__Craft Inc. BorderProtection__](http://dev.bukkit.org/bukkit-mods/craftinc-borderprotection/)
|
||||||
|
protect your worlds with a border players cannot cross.
|
||||||
|
|
||||||
|
* [__Craft Inc. Replicator__](http://dev.bukkit.org/bukkit-mods/craftinc-replicator/)
|
||||||
|
allows players to build a replicator to replicate blocks and other items. (still experimental)
|
||||||
|
|
||||||
|
* __Craft Inc. Scarecrow__
|
||||||
|
coming soon!
|
||||||
|
|
||||||
|
## Roadmap ##
|
||||||
|
* Per player permissions for using and managing gates.
|
||||||
|
* Horizontal gates.
|
||||||
|
|
||||||
|
## Bugs and other Problems ##
|
||||||
|
Please use our [_issue tracker_](https://github.com/craftinc/craftinc-gates/issues?state=open) on GitHub.
|
||||||
|
|
||||||
|
## Legal Information ##
|
||||||
|
This project is a fork of the original [_Ancient Gates_](https://github.com/bladedpenguin/minecraft-ancient-gates). It is licensed under the [_LGPL_](http://www.gnu.org/licenses/lgpl-3.0.txt) just like the Bukkit project. Thanks to all current and previous [_contributors_](https://github.com/craftinc/craftinc-gates/blob/development/AUTHORS.txt).
|
||||||
|
The font used for the Craft Inc. Gates logo is called [_MineCrafter 3_](http://www.minecraftforum.net/topic/892789-minecrafter-3-font-simply-easy/) and has been made available under the creative commons license. Thanks to Asherz08, MadPixel and Ashley Denham for this great font.
|
||||||
|
This plugin utilizes [_Hidendra's plugin metrics system_](http://mcstats.org), which means that the following information is collected and sent to mcstats.org: a unique identifier, the server's version of Java, whether the server is in offline or online mode, the plugin's version, the server's version, the OS version/name and architecture, the core count for the CPU, the number of players online, the Metrics version. __You can disable the stat collection via /plugins/PluginMetrics/config.yml if you wish.__
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- You may freely edit this file. See commented blocks below for -->
|
|
||||||
<!-- some examples of how to customize the build. -->
|
|
||||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
|
||||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
|
||||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
|
||||||
<!-- the Compile on Save feature is turned off for the project. -->
|
|
||||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
|
||||||
<!-- in the project's Project Properties dialog box.-->
|
|
||||||
<project name="AncientGates" default="default" basedir=".">
|
|
||||||
<description>Builds, tests, and runs the project AncientGates.</description>
|
|
||||||
<import file="nbproject/build-impl.xml"/>
|
|
||||||
<!--
|
|
||||||
|
|
||||||
There exist several targets which are by default empty and which can be
|
|
||||||
used for execution of your tasks. These targets are usually executed
|
|
||||||
before and after some main targets. They are:
|
|
||||||
|
|
||||||
-pre-init: called before initialization of project properties
|
|
||||||
-post-init: called after initialization of project properties
|
|
||||||
-pre-compile: called before javac compilation
|
|
||||||
-post-compile: called after javac compilation
|
|
||||||
-pre-compile-single: called before javac compilation of single file
|
|
||||||
-post-compile-single: called after javac compilation of single file
|
|
||||||
-pre-compile-test: called before javac compilation of JUnit tests
|
|
||||||
-post-compile-test: called after javac compilation of JUnit tests
|
|
||||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
|
||||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
|
||||||
-pre-jar: called before JAR building
|
|
||||||
-post-jar: called after JAR building
|
|
||||||
-post-clean: called after cleaning build products
|
|
||||||
|
|
||||||
(Targets beginning with '-' are not intended to be called on their own.)
|
|
||||||
|
|
||||||
Example of inserting an obfuscator after compilation could look like this:
|
|
||||||
|
|
||||||
<target name="-post-compile">
|
|
||||||
<obfuscate>
|
|
||||||
<fileset dir="${build.classes.dir}"/>
|
|
||||||
</obfuscate>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
For list of available properties check the imported
|
|
||||||
nbproject/build-impl.xml file.
|
|
||||||
|
|
||||||
|
|
||||||
Another way to customize the build is by overriding existing main targets.
|
|
||||||
The targets of interest are:
|
|
||||||
|
|
||||||
-init-macrodef-javac: defines macro for javac compilation
|
|
||||||
-init-macrodef-junit: defines macro for junit execution
|
|
||||||
-init-macrodef-debug: defines macro for class debugging
|
|
||||||
-init-macrodef-java: defines macro for class execution
|
|
||||||
-do-jar-with-manifest: JAR building (if you are using a manifest)
|
|
||||||
-do-jar-without-manifest: JAR building (if you are not using a manifest)
|
|
||||||
run: execution of project
|
|
||||||
-javadoc-build: Javadoc generation
|
|
||||||
test-report: JUnit report generation
|
|
||||||
|
|
||||||
An example of overriding the target for project execution could look like this:
|
|
||||||
|
|
||||||
<target name="run" depends="AncientGates-impl.jar">
|
|
||||||
<exec dir="bin" executable="launcher.exe">
|
|
||||||
<arg file="${dist.jar}"/>
|
|
||||||
</exec>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
Notice that the overridden target depends on the jar target and not only on
|
|
||||||
the compile target as the regular run target does. Again, for a list of available
|
|
||||||
properties which you can use, check the target you are overriding in the
|
|
||||||
nbproject/build-impl.xml file.
|
|
||||||
|
|
||||||
-->
|
|
||||||
</project>
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
## 2.4.0 ##
|
||||||
|
* Resolved issues with closing gates (special thanks to THCFrosD)
|
||||||
|
* Added support for riding through gates (with horses, mine carts, pigs and boats)
|
||||||
|
* Dynmap integration (extra plugin)
|
||||||
|
|
||||||
|
## 2.3.0 ##
|
||||||
|
* Added a command for setting the exit and opening a gate at once.
|
||||||
|
* Enabled the ability to change the gate block material.
|
||||||
|
* Added a command printing all nearby gates while highlighting them.
|
||||||
|
* Changed the info command to highlight gates.
|
||||||
|
* Updated the info command to print information about the nearest gate if no gate name got supplied.
|
||||||
|
|
||||||
|
## 2.2.1 ##
|
||||||
|
* Changed priority of some event listeners to solve problems with WorldGuard and other protection plugins.
|
||||||
|
|
||||||
|
## 2.2.0 ##
|
||||||
|
* Improved gate commands and shortcuts (have a look at the bukkit-dev page for more information).
|
||||||
|
* Improved overall performance.
|
||||||
|
* Added a configuration file (have a look at the bukkit-dev page for more information).
|
||||||
|
* Resolved issues with (random) teleports to the nether.
|
||||||
|
* Made it possible to create non hidden gates without a frame. (Turned off by default!)
|
||||||
|
* Changed the behavior regarding portal blocks. Starting with this version no blocks will be set by the plugin. All portal blocks will only be visible on client side.
|
||||||
|
* Added checks preventing the plugin from overwriting the gate storage file on error.
|
||||||
|
* Added the ability to change and disable messages on teleport and insufficient permissions via a config file.
|
||||||
|
|
||||||
|
## 2.1.2 ##
|
||||||
|
* Fixed a bug where players got teleported one block beside the real portal.
|
||||||
|
* Fixed a bug where gates with no location caused multiple exceptions.
|
||||||
|
|
||||||
|
## 2.1.1 ##
|
||||||
|
* Made the list command more reliable.
|
||||||
|
* Error messages will be displayed less frequent.
|
||||||
|
|
||||||
|
## 2.1.0 ##
|
||||||
|
* Command outputs are now colored.
|
||||||
|
* Fixed a bug where players in creative mode would not be teleported correctly.
|
||||||
|
* Made various commands available via the server console.
|
||||||
|
* Simplified command names.
|
||||||
|
* Improved permissions handling. (Added soft dependency for Vault.)
|
||||||
|
* A message will be displayed after a player has been teleported. There is also a message displayed if a player is not allowed to use a gate.
|
||||||
|
|
||||||
|
## 2.0.1a
|
||||||
|
* Fixed broken import for gates created with version 2.0.0
|
||||||
|
|
||||||
|
## 2.0.1
|
||||||
|
* Updated permissions to allow everyone to use gates by default.
|
||||||
|
* Fixed a bug where yaw had not been taken correctly into account while teleporting.
|
||||||
|
* Re-added persistence of yaw and pitch of gate locations and exits.
|
||||||
|
|
||||||
|
## 2.0.0
|
||||||
|
Initial release under new name
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
* __/gate allowRiding, ar [id]__
|
||||||
|
Update a gate so players can travel through it while riding.
|
||||||
|
|
||||||
|
* __/gate close, c [id]__
|
||||||
|
Closes a gate to prevent players from using it.
|
||||||
|
|
||||||
|
* __/gate denyRiding, dr [id]__
|
||||||
|
Update a gate so players can NOT travel through it while riding.
|
||||||
|
|
||||||
|
* __/gate delete, del, remove [id]__
|
||||||
|
Removes the gate from the game.
|
||||||
|
|
||||||
|
* __/gate exit, e [id]__
|
||||||
|
Changes the location where the gate will teleport players to your current location.
|
||||||
|
|
||||||
|
* __/gate exitopen, eo [id]__
|
||||||
|
Changes the location where the gate will teleport players to your current location. Also tries to open that gate afterwards.
|
||||||
|
|
||||||
|
* __/gate help, ? [page]__
|
||||||
|
Prints help pages.
|
||||||
|
|
||||||
|
* __/gate hide, h [id]__
|
||||||
|
Makes a gate NOT consist of gate blocks while open.
|
||||||
|
|
||||||
|
* __/gate info, i [id]__
|
||||||
|
Prints details about a certain gate. Will print information about the nearest gate if no _id_ is supplied. Also highlights the gate you're requesting information about.
|
||||||
|
|
||||||
|
* __/gate list, ls [page]__
|
||||||
|
Prints all available gates.
|
||||||
|
|
||||||
|
* __/gate location, lo [id]__
|
||||||
|
Sets the entrance of the gate to your current location.
|
||||||
|
|
||||||
|
* __/gate nearby, nb__
|
||||||
|
Prints the name of nearby gates. Also highlights them.
|
||||||
|
|
||||||
|
* __/gate new, n [id]__
|
||||||
|
Creates a gate at your current location.
|
||||||
|
|
||||||
|
* __/gate open, o [id]__
|
||||||
|
Open a gate so players can use it.
|
||||||
|
|
||||||
|
* __/gate rename, rn [current name] [new name]__
|
||||||
|
Changes the name/id of the gate.
|
||||||
|
|
||||||
|
* __/gate unhide,uh [id]__
|
||||||
|
Makes that gate visible.
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
Starting with version 2.2.0 some features are customizable via a configuration file.
|
||||||
|
|
||||||
|
The configuration file will be automatically created on the the first startup after
|
||||||
|
installing or updating the plugin.
|
||||||
|
|
||||||
|
|
||||||
|
The following keys and values are available:
|
||||||
|
|
||||||
|
|
||||||
|
* __maxGateBlocks__
|
||||||
|
A positive integer defining the maximum number of blocks a gate can consist of.
|
||||||
|
Note that increasing this value might slow down your server!
|
||||||
|
|
||||||
|
|
||||||
|
* __playerGateBlockUpdateRadius__
|
||||||
|
Defines the radius around a player where portal blocks are visible to that player.
|
||||||
|
Adjust this value when increasing or decreasing the view-distance on the server.
|
||||||
|
Only positive integer values are allowed.
|
||||||
|
|
||||||
|
|
||||||
|
* __checkForBrokenGateFrames__
|
||||||
|
Allowed values are _true_ and _false_ only. Setting this value to _false_ will disable
|
||||||
|
all checks for broken frames for non-hidden gates. Disabling frame block checks
|
||||||
|
might increase you server performance.
|
||||||
|
|
||||||
|
|
||||||
|
* __saveOnChanges__
|
||||||
|
Allowed values are _true_ and _false_ only. Disabling _save on changes_ might
|
||||||
|
increase server performance but gates will only be saved to disk when the plugin
|
||||||
|
gets disabled! This might lead to data loss on error.
|
||||||
|
|
||||||
|
|
||||||
|
* __gateTeleportMessage__
|
||||||
|
A string value going to displayed every time when a player travels using a gate. Will
|
||||||
|
only be displayed if _showTeleportMessage_ is set to _true_.
|
||||||
|
|
||||||
|
|
||||||
|
* __showTeleportMessage__
|
||||||
|
A boolean (_true_ or _false_) determining wether the _teleport message_ will
|
||||||
|
be displayed.
|
||||||
|
|
||||||
|
|
||||||
|
* __gateTeleportNoPermissionMessage__
|
||||||
|
A string value going to displayed every time when a player enters a gate and is not allowed to use that gate. Will only be displayed if _showTeleportNoPermissionMessage_
|
||||||
|
is set to _true_.
|
||||||
|
|
||||||
|
|
||||||
|
* __gateTeleportVehicleNotAllowedMessage__
|
||||||
|
A string value being displayed when a player tries to go through a gate while riding when riding through this gate is disabled. Will only be displayed if _showTeleportNoPermissionMessage_ is set to _true_.
|
||||||
|
|
||||||
|
* __showTeleportNoPermissionMessage__
|
||||||
|
A boolean (_true_ or _false_) determining wether the _no permission message_ will
|
||||||
|
be displayed.
|
||||||
|
|
||||||
|
|
||||||
|
* __gateMaterial__
|
||||||
|
A String representing the material all gates will consist of. Have a look at our [_Gate Material Page_](http://dev.bukkit.org/bukkit-plugins/craftinc-gates/pages/gate-materials/) for all possible values.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
Starting with version 2.3.0 different gate materials can be used. You can set them via the configuration file. The following Materials are currently defined:
|
||||||
|
|
||||||
|
* sapling
|
||||||
|
* water
|
||||||
|
* lava
|
||||||
|
* cobweb
|
||||||
|
* grass
|
||||||
|
* dead bush
|
||||||
|
* dandelion
|
||||||
|
* poppy
|
||||||
|
* brown mushroom
|
||||||
|
* red mushroom
|
||||||
|
* torch
|
||||||
|
* redstone torch (off)
|
||||||
|
* redstone torch (on)
|
||||||
|
* fence
|
||||||
|
* nether portal
|
||||||
|
* iron bars
|
||||||
|
* glass pane
|
||||||
|
* fence gate
|
||||||
|
* nether brick fence
|
||||||
|
* nether wart
|
||||||
|
* end portal
|
||||||
|
* cobblestone wall
|
||||||
|
|
||||||
|
|
||||||
|
Your favorite material is missing? Please contact us and we will see if we can add it.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
The following permissions are available: (Also have a look at the [Commands Page](http://dev.bukkit.org/bukkit-plugins/craftinc-gates/pages/commands/) to see if which commands can be executed with which permission set.)
|
||||||
|
|
||||||
|
* __craftincgates.info__
|
||||||
|
Gives access to info and list commands.
|
||||||
|
|
||||||
|
* __craftincgates.use__
|
||||||
|
Allows you to travel via gates.
|
||||||
|
|
||||||
|
* __craftincgates.manage__
|
||||||
|
Gives access to commands manipulating gates.
|
||||||
|
|
||||||
|
Craft Inc. Gates will use __[Vault](http://dev.bukkit.org/bukkit-mods/vault/)__'s permission system if Vault is installed on your server.
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
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.
|
|
||||||
+28
-5
@@ -1,7 +1,30 @@
|
|||||||
name: AncientGates
|
name: ${project.name}
|
||||||
version: 1.1
|
version: ${project.version}
|
||||||
main: org.mcteam.ancientgates.Plugin
|
description: A plugin to create gates for fast traveling.
|
||||||
|
softdepend: [Vault, Multiverse-Core, MultiWorld, RoyalCommands]
|
||||||
|
author: tomco, s1m0ne
|
||||||
|
authors: [oloflarsson, locutus, DrAgonmoray, s1m0ne, tomco]
|
||||||
|
website: http://dev.bukkit.org/bukkit-plugins/craftinc-gates/
|
||||||
|
|
||||||
|
main: de.craftinc.gates.Plugin
|
||||||
|
database: false
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
gate:
|
gate:
|
||||||
description: All of the AncientGates commands
|
description: All of the Craft Inc. Gates commands
|
||||||
usage: See documentation.
|
usage: See documentation or type '/gate help' while playing.
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
craftincgates.*:
|
||||||
|
description: Gives access to all Craft Inc. Gates commands.
|
||||||
|
children:
|
||||||
|
craftincgates.info: true
|
||||||
|
craftincgates.use: true
|
||||||
|
craftincgates.manage: true
|
||||||
|
craftincgates.info:
|
||||||
|
description: Gives access to info and list commands.
|
||||||
|
craftincgates.use:
|
||||||
|
default: true
|
||||||
|
description: Allows you to use open gates.
|
||||||
|
craftincgates.manage:
|
||||||
|
description: Gives access to commands manipulating gates.
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>de.craftinc</groupId>
|
||||||
|
<artifactId>CraftIncGates</artifactId>
|
||||||
|
<name>Craft Inc. Gates</name>
|
||||||
|
<url>http://dev.bukkit.org/bukkit-plugins/craftinc-gates/</url>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>2.4.1</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>1.7</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.7</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<!-- License -->
|
||||||
|
<licenses>
|
||||||
|
|
||||||
|
<license>
|
||||||
|
<name>GNU Lesser General Public License Version 3</name>
|
||||||
|
<url>https://www.gnu.org/licenses/lgpl-3.0-standalone.html</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>${project.name} ${project.version}</finalName>
|
||||||
|
<sourceDirectory>src</sourceDirectory>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<version>1.2.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>Run Test Bukkit Server</id>
|
||||||
|
<phase>install</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>exec</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<executable>${basedir}/scripts/test-deployment.sh</executable>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>1.7.1</version>
|
||||||
|
<configuration>
|
||||||
|
<artifactSet>
|
||||||
|
<includes>
|
||||||
|
<include>org.mcstats.bukkit:metrics</include>
|
||||||
|
</includes>
|
||||||
|
</artifactSet>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!--Spigot API-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot-api</artifactId>
|
||||||
|
<version>1.11-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--Bukkit API-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bukkit</groupId>
|
||||||
|
<artifactId>bukkit</artifactId>
|
||||||
|
<version>1.11-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--Vault-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.milkbowl.vault</groupId>
|
||||||
|
<artifactId>Vault</artifactId>
|
||||||
|
<version>1.6.6</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--Metrics-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mcstats.bukkit</groupId>
|
||||||
|
<artifactId>metrics</artifactId>
|
||||||
|
<version>R8-SNAPSHOT</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
|
||||||
|
<repository>
|
||||||
|
<id>spigot-repo</id>
|
||||||
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
|
||||||
|
<repository>
|
||||||
|
<id>vault-repo</id>
|
||||||
|
<url>http://nexus.hc.to/content/repositories/pub_releases</url>
|
||||||
|
</repository>
|
||||||
|
|
||||||
|
<repository>
|
||||||
|
<id>Plugin Metrics</id>
|
||||||
|
<url>http://repo.mcstats.org/content/repositories/public</url>
|
||||||
|
</repository>
|
||||||
|
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
maxGateBlocks: 50
|
||||||
|
playerGateBlockUpdateRadius: 64
|
||||||
|
highlightDuration: 5
|
||||||
|
saveOnChanges: true
|
||||||
|
checkForBrokenGateFrames: true
|
||||||
|
gateTeleportMessage: "Thank you for traveling with Craft Inc. Gates."
|
||||||
|
showTeleportMessage: true
|
||||||
|
gateTeleportNoPermissionMessage: "You are not allowed to use this gate!"
|
||||||
|
showTeleportNoPermissionMessage: true
|
||||||
|
gateTeleportVehicleNotAllowedMessage: "You must not use that gate while riding!"
|
||||||
|
gateMaterial: "nether portal"
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../plugin.yml
|
||||||
Executable
+160
@@ -0,0 +1,160 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(dirname "$0")
|
||||||
|
SERVICE='craftbukkit*.jar'
|
||||||
|
#USERNAME="minecraft"
|
||||||
|
CPU_COUNT=2
|
||||||
|
BUKKIT="$SCRIPT_DIR/../target/lib/$SERVICE"
|
||||||
|
INVOCATION="java -Xmx1000M -Xms300M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=$CPU_COUNT -XX:+AggressiveOpts -jar $BUKKIT nogui"
|
||||||
|
MCPATH="$SCRIPT_DIR/../bukkit-testserver"
|
||||||
|
|
||||||
|
if [ ! -d "$MCPATH" ]; then
|
||||||
|
mkdir -p "$MCPATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ME=$(whoami)
|
||||||
|
as_user() {
|
||||||
|
#if [ $ME == $USERNAME ] ; then
|
||||||
|
bash -c "$1"
|
||||||
|
#else
|
||||||
|
#su - $USERNAME -c "$1"
|
||||||
|
#fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_start() {
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "Tried to start but $SERVICE was already running!"
|
||||||
|
else
|
||||||
|
echo "$SERVICE was not running... starting."
|
||||||
|
cd "$MCPATH"
|
||||||
|
as_user "cd "$MCPATH" && screen -dmS minecraft $INVOCATION"
|
||||||
|
sleep 7
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE is now running."
|
||||||
|
else
|
||||||
|
echo "Could not start $SERVICE."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_stop() {
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE is running... stopping."
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
|
||||||
|
sleep 2
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'"
|
||||||
|
sleep 6
|
||||||
|
else
|
||||||
|
echo "$SERVICE was not running."
|
||||||
|
fi
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE could not be shut down... still running."
|
||||||
|
else
|
||||||
|
echo "$SERVICE is shut down."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_save() {
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE is running... saving."
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
|
||||||
|
else
|
||||||
|
echo "$SERVICE was not running."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_reload() {
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE is running... reloading."
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"reload\"\015'"
|
||||||
|
else
|
||||||
|
echo "$SERVICE was not running."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_reload_or_start() {
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE was already running! Doing a reload now!"
|
||||||
|
mc_reload
|
||||||
|
else
|
||||||
|
echo "$SERVICE was not running... starting."
|
||||||
|
cd "$MCPATH"
|
||||||
|
as_user "cd \"$MCPATH\" && screen -dmS minecraft $INVOCATION"
|
||||||
|
sleep 7
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE is now running."
|
||||||
|
else
|
||||||
|
echo "Could not start $SERVICE."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mc_ddidderr_admin() {
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE is running... making ddidder to admin and reloading permissions."
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"pex user ddidderr group set admin\"\015'"
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"pex reload\"\015'"
|
||||||
|
else
|
||||||
|
echo "$SERVICE was not running."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
echo "Starting Minecraft..."
|
||||||
|
mc_start
|
||||||
|
echo "DONE"
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
echo "Stopping Minecraft..."
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN!\"\015'"
|
||||||
|
mc_stop
|
||||||
|
echo "DONE"
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER REBOOT IN 10 SECONDS.\"\015'"
|
||||||
|
$0 stop
|
||||||
|
sleep 1
|
||||||
|
$0 start
|
||||||
|
;;
|
||||||
|
reload)
|
||||||
|
mc_reload
|
||||||
|
;;
|
||||||
|
reload_or_start)
|
||||||
|
echo "Starting or reloading Minecraft..."
|
||||||
|
mc_reload_or_start
|
||||||
|
echo "DONE"
|
||||||
|
;;
|
||||||
|
ddidderr_admin)
|
||||||
|
mc_ddidderr_admin
|
||||||
|
;;
|
||||||
|
connected)
|
||||||
|
as_user "screen -p 0 -S minecraft -X eval 'stuff \"who\"\015'"
|
||||||
|
sleep 2s
|
||||||
|
tac "$MCPATH"/server.log | grep -m 1 "Connected"
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
if ps ax | grep -v grep | grep -v -i SCREEN | grep "craftbukkit" > /dev/null
|
||||||
|
then
|
||||||
|
echo "$SERVICE is running."
|
||||||
|
else
|
||||||
|
echo "$SERVICE is not running."
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
save)
|
||||||
|
mc_save
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: /etc/init.d/minecraft {start|stop|restart|connected|status}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(dirname "$0")"
|
||||||
|
|
||||||
|
DEVELOPER=$(whoami)
|
||||||
|
|
||||||
|
if [ $DEVELOPER = "tobi" ]; then
|
||||||
|
BUKKIT_DIR="$HOME/minecraft/testbuk"
|
||||||
|
PLUGIN_DIR="$HOME/minecraft/testbuk/plugins"
|
||||||
|
START_STOP_SCRIPT="$BUKKIT_DIR/../minecraft.sh"
|
||||||
|
else
|
||||||
|
BUKKIT_DIR="$SCRIPT_DIR/../bukkit-testserver"
|
||||||
|
PLUGIN_DIR="$SCRIPT_DIR/../bukkit-testserver/plugins"
|
||||||
|
START_STOP_SCRIPT="$SCRIPT_DIR/minecraft.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# TODO: This is a bad solution! Maven should write necessary information into an extra file.
|
||||||
|
ARTIFACT_ID="$(grep -C5 '<groupId>de.craftinc' "$SCRIPT_DIR/../pom.xml" | grep '<name>' | sed 's/[ \t]*<name>//g' | sed 's/<\/name>[ \t]*//g')"
|
||||||
|
|
||||||
|
# TODO: This is a bad solution! Maven should write necessary information into an extra file.
|
||||||
|
VERSION="$(grep -C5 '<groupId>de.craftinc' "$SCRIPT_DIR/../pom.xml" | grep '<version>' | sed 's/[ \t]*<version>//g' | sed 's/<\/version>[ \t]*//g')"
|
||||||
|
|
||||||
|
mkdir -p "$PLUGIN_DIR"
|
||||||
|
|
||||||
|
cp "$SCRIPT_DIR/../target/$ARTIFACT_ID $VERSION".jar "$PLUGIN_DIR/"
|
||||||
|
|
||||||
|
echo -e "ddidderr\nmice_on_drugs\nMochaccino\nbeuth_el_max" > "$BUKKIT_DIR/ops.txt"
|
||||||
|
|
||||||
|
$START_STOP_SCRIPT reload_or_start
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.GatesManager;
|
||||||
|
import de.craftinc.gates.listeners.*;
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.ConfigurationUtil;
|
||||||
|
import net.milkbowl.vault.permission.Permission;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.serialization.ConfigurationSerialization;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import de.craftinc.gates.commands.*;
|
||||||
|
import org.mcstats.Metrics;
|
||||||
|
|
||||||
|
public class Plugin extends JavaPlugin {
|
||||||
|
private static Plugin instance;
|
||||||
|
|
||||||
|
private String baseCommand;
|
||||||
|
protected List<BaseCommand> commands = new ArrayList<>();
|
||||||
|
|
||||||
|
private GatesManager gatesManager = new GatesManager();
|
||||||
|
|
||||||
|
private PermissionController permissionController = new PermissionController();
|
||||||
|
|
||||||
|
private PlayerMoveListener moveListener;
|
||||||
|
private VehicleMoveListener vehicleListener;
|
||||||
|
private PlayerTeleportListener teleportListener = new PlayerTeleportListener();
|
||||||
|
private PlayerRespawnListener respawnListener = new PlayerRespawnListener();
|
||||||
|
private PlayerChangedWorldListener worldChangeListener = new PlayerChangedWorldListener();
|
||||||
|
private PlayerJoinListener joinListener = new PlayerJoinListener();
|
||||||
|
private BlockBreakListener blockBreakListener = new BlockBreakListener();
|
||||||
|
|
||||||
|
public Plugin() {
|
||||||
|
instance = this;
|
||||||
|
moveListener = new PlayerMoveListener(this);
|
||||||
|
vehicleListener = new VehicleMoveListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Plugin getPlugin() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GatesManager getGatesManager() {
|
||||||
|
return gatesManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
ConfigurationSerialization.registerClass(Gate.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupPermissions() {
|
||||||
|
if (getServer().getPluginManager().getPlugin("Vault") == null) {
|
||||||
|
log("Not using setup permission provider provided by Vault.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisteredServiceProvider<Permission> rsp = getServer().getServicesManager().getRegistration(Permission.class);
|
||||||
|
|
||||||
|
if (rsp != null) {
|
||||||
|
log("Using permission provider provided by Vault.");
|
||||||
|
permissionController.setPermission(rsp.getProvider());
|
||||||
|
} else {
|
||||||
|
log("Not using setup permission provider provided by Vault.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
gatesManager.saveGatesToDisk();
|
||||||
|
log("Disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
// Setup Metrics
|
||||||
|
try {
|
||||||
|
Metrics metrics = new Metrics(this);
|
||||||
|
metrics.start();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log("Failed to start metrics!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup configuration
|
||||||
|
this.saveDefaultConfig();
|
||||||
|
|
||||||
|
// Setup permissions
|
||||||
|
setupPermissions();
|
||||||
|
|
||||||
|
// Add the commands
|
||||||
|
commands.add(new CommandHelp());
|
||||||
|
commands.add(new CommandNew());
|
||||||
|
commands.add(new CommandRemove());
|
||||||
|
commands.add(new CommandLocation());
|
||||||
|
commands.add(new CommandExit());
|
||||||
|
commands.add(new CommandTriggerOpen());
|
||||||
|
commands.add(new CommandRename());
|
||||||
|
commands.add(new CommandList());
|
||||||
|
commands.add(new CommandInfo());
|
||||||
|
commands.add(new CommandNearby());
|
||||||
|
commands.add(new CommandTriggerVehicles());
|
||||||
|
commands.add(new CommandMaterial());
|
||||||
|
commands.add(new CommandTeleport());
|
||||||
|
|
||||||
|
// Register events
|
||||||
|
this.registerEventListeners();
|
||||||
|
|
||||||
|
// Load gates
|
||||||
|
boolean success = gatesManager.loadGatesFromDisk();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
log("Enabled");
|
||||||
|
} else {
|
||||||
|
PluginManager pm = this.getServer().getPluginManager();
|
||||||
|
pm.disablePlugin(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PermissionController getPermissionController() {
|
||||||
|
return permissionController;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerEventListeners() {
|
||||||
|
PluginManager pm = this.getServer().getPluginManager();
|
||||||
|
|
||||||
|
pm.registerEvents(this.moveListener, this);
|
||||||
|
pm.registerEvents(this.teleportListener, this);
|
||||||
|
pm.registerEvents(this.respawnListener, this);
|
||||||
|
pm.registerEvents(this.worldChangeListener, this);
|
||||||
|
pm.registerEvents(this.joinListener, this);
|
||||||
|
pm.registerEvents(this.vehicleListener, this);
|
||||||
|
|
||||||
|
if (getConfig().getBoolean(ConfigurationUtil.confCheckForBrokenGateFramesKey)) {
|
||||||
|
pm.registerEvents(this.blockBreakListener, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------- //
|
||||||
|
// Commands
|
||||||
|
// -------------------------------------------- //
|
||||||
|
|
||||||
|
public String getBaseCommand() {
|
||||||
|
if (this.baseCommand != null)
|
||||||
|
return this.baseCommand;
|
||||||
|
|
||||||
|
Map<String, Map<String, Object>> Commands = this.getDescription().getCommands();
|
||||||
|
|
||||||
|
this.baseCommand = Commands.keySet().iterator().next();
|
||||||
|
|
||||||
|
return this.baseCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
||||||
|
List<String> parameters = new ArrayList<>(Arrays.asList(args));
|
||||||
|
this.handleCommand(sender, parameters);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleCommand(CommandSender sender, List<String> parameters) {
|
||||||
|
if (parameters.size() == 0) {
|
||||||
|
this.commands.get(0).execute(sender, parameters);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandName = parameters.get(0).toLowerCase();
|
||||||
|
parameters.remove(0);
|
||||||
|
|
||||||
|
for (BaseCommand command : this.commands) {
|
||||||
|
if (command.getAliases().contains(commandName)) {
|
||||||
|
command.execute(sender, parameters);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage(ChatColor.RED + "Unknown gate-command \"" + commandName + "\"." +
|
||||||
|
ChatColor.GREEN + " Try " + "/" + getBaseCommand() + " help");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Logging
|
||||||
|
*/
|
||||||
|
public static void log(String msg) {
|
||||||
|
log(Level.INFO, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void log(Level level, String msg) {
|
||||||
|
Logger.getLogger("Minecraft").log(level, "[" + instance.getDescription().getFullName() + "] " + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.ConfigurationUtil;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.controllers.GatesManager;
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.util.TextUtil;
|
||||||
|
|
||||||
|
public abstract class BaseCommand {
|
||||||
|
PermissionController permissionController;
|
||||||
|
GatesManager gatesManager;
|
||||||
|
|
||||||
|
List<String> aliases = new ArrayList<>();
|
||||||
|
List<String> requiredParameters = new ArrayList<>();
|
||||||
|
List<String> optionalParameters = new ArrayList<>();
|
||||||
|
|
||||||
|
String helpDescription = "no description";
|
||||||
|
|
||||||
|
List<String> parameters;
|
||||||
|
CommandSender sender;
|
||||||
|
Player player;
|
||||||
|
Gate gate;
|
||||||
|
|
||||||
|
boolean senderMustBePlayer = true;
|
||||||
|
boolean hasGateParam = true;
|
||||||
|
|
||||||
|
String requiredPermission;
|
||||||
|
boolean needsPermissionAtCurrentLocation;
|
||||||
|
|
||||||
|
boolean shouldPersistToDisk;
|
||||||
|
|
||||||
|
public List<String> getAliases() {
|
||||||
|
return aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseCommand() {
|
||||||
|
gatesManager = Plugin.getPlugin().getGatesManager();
|
||||||
|
permissionController = Plugin.getPlugin().getPermissionController();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(CommandSender sender, List<String> parameters) {
|
||||||
|
this.sender = sender;
|
||||||
|
this.parameters = parameters;
|
||||||
|
|
||||||
|
if (!this.validateCall()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sender instanceof Player) {
|
||||||
|
this.player = (Player)sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.perform();
|
||||||
|
|
||||||
|
if (this.shouldPersistToDisk && getSaveOnChanges()) {
|
||||||
|
gatesManager.saveGatesToDisk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected void perform();
|
||||||
|
|
||||||
|
void sendMessage(String message) {
|
||||||
|
sender.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendMessage(List<String> messages) {
|
||||||
|
for (String message : messages) {
|
||||||
|
this.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean setGateUsingParameter(String param) {
|
||||||
|
if (!gatesManager.gateExists(param)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
gate = gatesManager.getGateWithId(param);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will return false if a gate is required for this command but this.gate == null.
|
||||||
|
*/
|
||||||
|
boolean hasPermission() {
|
||||||
|
if (needsPermissionAtCurrentLocation) {
|
||||||
|
return permissionController.hasPermission(sender, requiredPermission);
|
||||||
|
} else {
|
||||||
|
return permissionController.hasPermission(sender, gate, requiredPermission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Help and usage description
|
||||||
|
*/
|
||||||
|
|
||||||
|
String getUsageTemplate(boolean withDescription) {
|
||||||
|
String ret = "";
|
||||||
|
|
||||||
|
ret += ChatColor.AQUA;
|
||||||
|
ret += "/" + Plugin.getPlugin().getBaseCommand() + " " + TextUtil.implode(getAliases(), ",") + " ";
|
||||||
|
|
||||||
|
List<String> parts = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String requiredParameter : requiredParameters) {
|
||||||
|
parts.add("[" + requiredParameter + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String optionalParameter : optionalParameters) {
|
||||||
|
parts.add("*[" + optionalParameter + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ret += ChatColor.DARK_AQUA;
|
||||||
|
ret += TextUtil.implode(parts, " ");
|
||||||
|
|
||||||
|
if (withDescription) {
|
||||||
|
ret += " ";
|
||||||
|
ret += ChatColor.YELLOW;
|
||||||
|
ret += helpDescription;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateCall() {
|
||||||
|
boolean allParametersThere = parameters.size() >= requiredParameters.size();
|
||||||
|
boolean senderIsPlayer = this.sender instanceof Player;
|
||||||
|
boolean hasGateParameter = false;
|
||||||
|
|
||||||
|
if (this.hasGateParam && this.parameters.size() > 0 && this.setGateUsingParameter(this.parameters.get(0))) {
|
||||||
|
hasGateParameter = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean senderHasPermission = this.hasPermission();
|
||||||
|
boolean valid;
|
||||||
|
|
||||||
|
if (this.senderMustBePlayer && !senderIsPlayer) {
|
||||||
|
sendMessage(ChatColor.RED + "This command can only be used by in-game players.");
|
||||||
|
valid = false;
|
||||||
|
} else {
|
||||||
|
if (!allParametersThere) {
|
||||||
|
sendMessage(ChatColor.RED + "Some parameters are missing! " +
|
||||||
|
ChatColor.AQUA + "Usage: " +
|
||||||
|
getUsageTemplate(false)
|
||||||
|
);
|
||||||
|
valid = false;
|
||||||
|
} else if ((!senderHasPermission && this.hasGateParam) ||
|
||||||
|
(!senderHasPermission) ||
|
||||||
|
(this.hasGateParam && !hasGateParameter)) {
|
||||||
|
|
||||||
|
sendMessage(ChatColor.RED +
|
||||||
|
"You either provided a invalid gate or do not have permission to " +
|
||||||
|
this.helpDescription.toLowerCase()
|
||||||
|
);
|
||||||
|
valid = false;
|
||||||
|
} else {
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getSaveOnChanges() {
|
||||||
|
FileConfiguration config = Plugin.getPlugin().getConfig();
|
||||||
|
return config.getBoolean(ConfigurationUtil.confSaveOnChangesKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
|
||||||
|
abstract class BaseLocationCommand extends BaseCommand {
|
||||||
|
|
||||||
|
Location getValidPlayerLocation() {
|
||||||
|
// The player might stand in a half block or a sign or whatever
|
||||||
|
// Therefore we load some extra locations and blocks
|
||||||
|
Location location = player.getLocation().clone();
|
||||||
|
Block playerBlock = location.getBlock();
|
||||||
|
Block upBlock = playerBlock.getRelative(BlockFace.UP);
|
||||||
|
|
||||||
|
if (playerBlock.getType() == Material.AIR) {
|
||||||
|
return location;
|
||||||
|
} else if (upBlock.getType() == Material.AIR) {
|
||||||
|
return location.add(0, 1, 0);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
public class CommandExit extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandExit() {
|
||||||
|
aliases.add("exit");
|
||||||
|
aliases.add("e");
|
||||||
|
requiredParameters.add("id");
|
||||||
|
helpDescription = "Change exit of location.";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
needsPermissionAtCurrentLocation = true;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
senderMustBePlayer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
try {
|
||||||
|
Location oldExit = gate.getExit();
|
||||||
|
gate.setExit(player.getLocation());
|
||||||
|
sendMessage(ChatColor.GREEN + "The exit of gate '" + gate.getId() + "' is now where you stand.");
|
||||||
|
gatesManager.handleGateExitChange(gate, oldExit);
|
||||||
|
} catch (Exception e) {
|
||||||
|
GateBlockChangeSender.updateGateBlocks(gate);
|
||||||
|
sendMessage(ChatColor.RED + "Setting the exit for the gate failed! See server log for more information");
|
||||||
|
Plugin.log(Level.WARNING, e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.TextUtil;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CommandHelp extends BaseCommand {
|
||||||
|
|
||||||
|
private static List<String> help;
|
||||||
|
|
||||||
|
public CommandHelp() {
|
||||||
|
aliases.add("help");
|
||||||
|
aliases.add("?");
|
||||||
|
helpDescription = "prints this help page";
|
||||||
|
requiredPermission = PermissionController.permissionInfo;
|
||||||
|
hasGateParam = false;
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = false;
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
sendMessage(TextUtil.titleSize("Craft Inc. Gates Help"));
|
||||||
|
sendMessage(getHelp());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getHelp() {
|
||||||
|
if (help == null) {
|
||||||
|
help = Arrays.asList(
|
||||||
|
new CommandHelp().getUsageTemplate(true),
|
||||||
|
new CommandNew().getUsageTemplate(true),
|
||||||
|
new CommandRemove().getUsageTemplate(true),
|
||||||
|
new CommandLocation().getUsageTemplate(true),
|
||||||
|
new CommandExit().getUsageTemplate(true),
|
||||||
|
new CommandTriggerOpen().getUsageTemplate(true),
|
||||||
|
new CommandRename().getUsageTemplate(true),
|
||||||
|
new CommandList().getUsageTemplate(true),
|
||||||
|
new CommandInfo().getUsageTemplate(true),
|
||||||
|
new CommandNearby().getUsageTemplate(true),
|
||||||
|
new CommandTriggerVehicles().getUsageTemplate(true),
|
||||||
|
new CommandTeleport().getUsageTemplate(true),
|
||||||
|
new CommandMaterial().getUsageTemplate(true)
|
||||||
|
);
|
||||||
|
Collections.sort(help);
|
||||||
|
}
|
||||||
|
|
||||||
|
return help;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.util.TextUtil;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
public class CommandInfo extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandInfo() {
|
||||||
|
aliases.add("info");
|
||||||
|
aliases.add("i");
|
||||||
|
optionalParameters.add("id");
|
||||||
|
helpDescription = "Print detailed information about a certain or the closest gate.";
|
||||||
|
requiredPermission = PermissionController.permissionInfo;
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = false;
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
hasGateParam = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
if (this.parameters.size() > 0) {
|
||||||
|
|
||||||
|
if (!this.setGateUsingParameter(this.parameters.get(0))) {
|
||||||
|
sendMessage(ChatColor.RED + "You either provided a invalid gate or do not have permission to " + this.helpDescription.toLowerCase());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(TextUtil.titleSize("Information about: '" + ChatColor.WHITE + gate.getId() + ChatColor.YELLOW + "'"));
|
||||||
|
} else {
|
||||||
|
boolean senderIsPlayer = this.sender instanceof Player;
|
||||||
|
|
||||||
|
if (!senderIsPlayer) {
|
||||||
|
sendMessage(ChatColor.RED + "Only ingame players can perform this command without a supplied gate id!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player p = (Player) this.sender;
|
||||||
|
this.gate = gatesManager.getNearestGate(p.getLocation());
|
||||||
|
|
||||||
|
if (!this.hasPermission() || this.gate == null) {
|
||||||
|
sendMessage(ChatColor.RED + "There is either no gate nearby or you do not have permission to " + this.helpDescription.toLowerCase());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin.log(this.gate.toString());
|
||||||
|
|
||||||
|
sendMessage(TextUtil.titleSize("Information about closest gate: '" + ChatColor.WHITE + gate.getId() + ChatColor.YELLOW + "'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
String openMessage = ChatColor.DARK_AQUA + "This gate is";
|
||||||
|
|
||||||
|
if (gate.isOpen())
|
||||||
|
openMessage += ChatColor.AQUA + " open";
|
||||||
|
else
|
||||||
|
openMessage += ChatColor.AQUA + " closed";
|
||||||
|
|
||||||
|
openMessage += ".\n";
|
||||||
|
|
||||||
|
sendMessage(openMessage);
|
||||||
|
|
||||||
|
if (gate.getLocation() != null)
|
||||||
|
sendMessage(ChatColor.DARK_AQUA + "location: " + ChatColor.AQUA + "( " + (int) gate.getLocation().getX() +
|
||||||
|
" | " + (int) gate.getLocation().getY() + " | " + (int) gate.getLocation().getZ() + " ) in " +
|
||||||
|
gate.getLocation().getWorld().getName());
|
||||||
|
else
|
||||||
|
sendMessage(ChatColor.DARK_AQUA + "NOTE: this gate has no location");
|
||||||
|
|
||||||
|
if (gate.getExit() != null)
|
||||||
|
sendMessage(ChatColor.DARK_AQUA + "exit: " + ChatColor.AQUA + "( " + (int) gate.getExit().getX() + " | "
|
||||||
|
+ (int) gate.getExit().getY() + " | " + (int) gate.getExit().getZ() + " ) in " +
|
||||||
|
gate.getExit().getWorld().getName());
|
||||||
|
else
|
||||||
|
sendMessage(ChatColor.DARK_AQUA + "NOTE: this gate has no exit");
|
||||||
|
|
||||||
|
|
||||||
|
if (gate.getAllowsVehicles())
|
||||||
|
sendMessage(ChatColor.DARK_AQUA + "You can ride through this gate.");
|
||||||
|
|
||||||
|
sendMessage(ChatColor.DARK_AQUA + "This gate is made of "
|
||||||
|
+ ChatColor.AQUA + gate.getMaterial() + ChatColor.DARK_AQUA + ".");
|
||||||
|
|
||||||
|
if (this.sender instanceof Player) {
|
||||||
|
HashSet<Gate> set = new HashSet<>();
|
||||||
|
set.add(this.gate);
|
||||||
|
|
||||||
|
GateBlockChangeSender.temporaryHighlightGatesFrames((Player)this.sender, set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.util.TextUtil;
|
||||||
|
|
||||||
|
public class CommandList extends BaseCommand {
|
||||||
|
|
||||||
|
private static final int linesPerPage = 15;
|
||||||
|
|
||||||
|
/* this is actually not true. the font used by Minecraft is not
|
||||||
|
monospaced. but there seems to be no (easy) way to calculate
|
||||||
|
the drawing-size of a string.
|
||||||
|
*/
|
||||||
|
private static final int charactersPerLine = 52;
|
||||||
|
|
||||||
|
public CommandList() {
|
||||||
|
aliases.add("list");
|
||||||
|
aliases.add("ls");
|
||||||
|
|
||||||
|
optionalParameters.add("page");
|
||||||
|
hasGateParam = false;
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
|
||||||
|
helpDescription = "lists all availible gates.";
|
||||||
|
|
||||||
|
requiredPermission = PermissionController.permissionInfo;
|
||||||
|
shouldPersistToDisk = false;
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
int page = this.getPageParameter();
|
||||||
|
List<String> allPages = this.pagedGateIds();
|
||||||
|
|
||||||
|
if (allPages == null) { // no gates exist
|
||||||
|
sendMessage(ChatColor.RED + "There are no gates yet. " + ChatColor.RESET +
|
||||||
|
"(Note that you might not be allowed to get information about certain gates)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page > allPages.size() || page < 1) {
|
||||||
|
sendMessage(ChatColor.RED + "The requested page is not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String message = TextUtil.titleSize("List of all gates (" + page + "/" + allPages.size() + ")") + "\n";
|
||||||
|
message += allPages.get(page - 1);
|
||||||
|
|
||||||
|
sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> linesOfGateIds(List<String> gates) {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
List<String> gateIdsForCurrentLine = new ArrayList<>();
|
||||||
|
int numCharactersInCurrentLine = 0;
|
||||||
|
|
||||||
|
while (index < gates.size()) {
|
||||||
|
String gateId = gates.get(index);
|
||||||
|
int gateIdLength = gateId.length() + 2; // actual length + comma + whitespace
|
||||||
|
|
||||||
|
if (gateIdLength > charactersPerLine && numCharactersInCurrentLine == 0) { // special case: very long gate id
|
||||||
|
gateIdsForCurrentLine = new ArrayList<>();
|
||||||
|
numCharactersInCurrentLine = 0;
|
||||||
|
|
||||||
|
while ((gateId.length() + 2) > charactersPerLine) {
|
||||||
|
int cutPos = charactersPerLine;
|
||||||
|
|
||||||
|
// is the id too long to add comma and whitespace but not longer than the line?
|
||||||
|
if (gateId.length() <= charactersPerLine) {
|
||||||
|
cutPos -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.add(gateId.substring(0, cutPos));
|
||||||
|
gateId = gateId.substring(cutPos, gateId.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
gateIdsForCurrentLine.add(gateId);
|
||||||
|
|
||||||
|
numCharactersInCurrentLine += gateId.length();
|
||||||
|
index++;
|
||||||
|
} else if ((numCharactersInCurrentLine + gateIdLength) <= charactersPerLine) { // gate fits into current line
|
||||||
|
gateIdsForCurrentLine.add(gateId);
|
||||||
|
numCharactersInCurrentLine += gateIdLength;
|
||||||
|
|
||||||
|
index++;
|
||||||
|
} else { // the current gate does not fit on the
|
||||||
|
lines.add(TextUtil.implode(gateIdsForCurrentLine, ", ") + ", ");
|
||||||
|
|
||||||
|
gateIdsForCurrentLine = new ArrayList<>();
|
||||||
|
numCharactersInCurrentLine = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.add(TextUtil.implode(gateIdsForCurrentLine, ", "));
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String intToTitleString(int i, boolean addPreviousPageNote, boolean addNextPageNote) {
|
||||||
|
String retVal = ChatColor.DARK_AQUA + "";
|
||||||
|
|
||||||
|
if (i < 26) {
|
||||||
|
retVal += (char) (i + 65);
|
||||||
|
} else if (i == 26) {
|
||||||
|
retVal += "0-9";
|
||||||
|
} else {
|
||||||
|
retVal += "!@#$";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addPreviousPageNote && addNextPageNote) {
|
||||||
|
retVal += " (more on previous and next page)";
|
||||||
|
} else if (addPreviousPageNote) {
|
||||||
|
retVal += " (more on previous page)";
|
||||||
|
} else if (addNextPageNote) {
|
||||||
|
retVal += " (more on next page)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for getting a collection of gates the player is allowed to see.
|
||||||
|
*/
|
||||||
|
private Collection<Gate> getAllGates() {
|
||||||
|
Collection<Gate> gates = gatesManager.allGates();
|
||||||
|
// create a copy since we cannot iterate over a collection while modifying it!
|
||||||
|
Collection<Gate> gatesCopy = new ArrayList<>(gates);
|
||||||
|
|
||||||
|
for (Gate gate : gatesCopy) {
|
||||||
|
if (!this.permissionController.hasPermission(this.sender, gate, this.requiredPermission)) {
|
||||||
|
gates.remove(gate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts all gates by there first character.
|
||||||
|
* Puts gates in corresponding Lists: (all returned lists will be sorted alphabetically)
|
||||||
|
* list 0-25: a,b,c,..,z
|
||||||
|
* list 26: 0-9
|
||||||
|
* list 27: other
|
||||||
|
*/
|
||||||
|
private static List<List<String>> gatesSortedByName(Collection<Gate> allGates) {
|
||||||
|
// create the lists
|
||||||
|
List<List<String>> ids = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < 28; i++) {
|
||||||
|
ids.add(new ArrayList<String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// put all gates into correct lists
|
||||||
|
for (Gate gate : allGates) {
|
||||||
|
String id = gate.getId();
|
||||||
|
int first = id.charAt(0);
|
||||||
|
|
||||||
|
if (first > 96 && first < 123) { // convert lower case chars
|
||||||
|
first -= 97;
|
||||||
|
} else if (first > 64 && first < 91) { // convert upper case chars
|
||||||
|
first -= 65;
|
||||||
|
} else if (first > 47 && first < 58) { // convert numbers
|
||||||
|
first = 26;
|
||||||
|
} else { // everything else
|
||||||
|
first = 27;
|
||||||
|
}
|
||||||
|
|
||||||
|
ids.get(first).add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort everything
|
||||||
|
for (int i = 0; i < 28; i++) {
|
||||||
|
Collections.sort(ids.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of strings.
|
||||||
|
* Each string is the text for a page.
|
||||||
|
* The maximum number of lines per page is 'linesPerPage' minus 1.
|
||||||
|
* Will return an empty list if no gates are availible.
|
||||||
|
*/
|
||||||
|
private List<String> pagedGateIds() {
|
||||||
|
Collection<Gate> gates = this.getAllGates();
|
||||||
|
|
||||||
|
if (gates.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<List<String>> gatesSortedByName = gatesSortedByName(gates);
|
||||||
|
List<String> allPages = new ArrayList<>();
|
||||||
|
int linesLeftOnPage = linesPerPage - 1;
|
||||||
|
String currentPageString = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < gatesSortedByName.size(); i++) {
|
||||||
|
|
||||||
|
List<String> currentGates = gatesSortedByName.get(i);
|
||||||
|
|
||||||
|
if (currentGates.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> currentGatesAsLines = linesOfGateIds(currentGates);
|
||||||
|
boolean moreGatesOnLastPage = false;
|
||||||
|
|
||||||
|
while (!currentGatesAsLines.isEmpty()) {
|
||||||
|
|
||||||
|
if (linesLeftOnPage < 2) {
|
||||||
|
currentPageString = currentPageString.substring(0, currentPageString.length() - 2); // remove newlines add the end of the page
|
||||||
|
allPages.add(currentPageString);
|
||||||
|
currentPageString = "";
|
||||||
|
|
||||||
|
linesLeftOnPage = linesPerPage - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate number of lines to add to current page
|
||||||
|
int linesNecessaryForCurrentGates = currentGatesAsLines.size();
|
||||||
|
int linesToFill;
|
||||||
|
boolean moreGatesOnNextPage;
|
||||||
|
|
||||||
|
if (linesNecessaryForCurrentGates < linesLeftOnPage) {
|
||||||
|
linesToFill = linesNecessaryForCurrentGates;
|
||||||
|
moreGatesOnNextPage = false;
|
||||||
|
} else {
|
||||||
|
linesToFill = linesLeftOnPage - 1;
|
||||||
|
moreGatesOnNextPage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add title
|
||||||
|
currentPageString += intToTitleString(i, moreGatesOnLastPage, moreGatesOnNextPage);
|
||||||
|
currentPageString += ChatColor.AQUA;
|
||||||
|
linesLeftOnPage--;
|
||||||
|
|
||||||
|
// add gate lines
|
||||||
|
for (int j = 0; j < linesToFill; j++) {
|
||||||
|
currentPageString += currentGatesAsLines.get(j) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove lines added
|
||||||
|
for (int j = 0; j < linesToFill; j++) {
|
||||||
|
currentGatesAsLines.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
moreGatesOnLastPage = linesNecessaryForCurrentGates >= linesLeftOnPage;
|
||||||
|
linesLeftOnPage -= linesToFill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the last page
|
||||||
|
if (!currentPageString.isEmpty()) {
|
||||||
|
currentPageString = currentPageString.substring(0, currentPageString.length() - 2); // remove newlines add the end of the page
|
||||||
|
allPages.add(currentPageString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int getPageParameter() {
|
||||||
|
int page = 1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
page = new Integer(parameters.get(0));
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
|
public class CommandLocation extends BaseLocationCommand {
|
||||||
|
|
||||||
|
public CommandLocation() {
|
||||||
|
aliases.add("location");
|
||||||
|
aliases.add("lo");
|
||||||
|
|
||||||
|
requiredParameters.add("id");
|
||||||
|
helpDescription = "Set the entrance of the gate to your current location.";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
|
||||||
|
needsPermissionAtCurrentLocation = true;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
senderMustBePlayer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
Location playerLocation = getValidPlayerLocation();
|
||||||
|
|
||||||
|
if (playerLocation == null) {
|
||||||
|
sendMessage("There is not enough room for a gate to open here");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location oldLocation = gate.getLocation();
|
||||||
|
Set<Location> oldGateBlockLocations = gate.getGateBlockLocations();
|
||||||
|
Set<Block> oldFrameBlocks = gate.getGateFrameBlocks();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (gate.isOpen()) {
|
||||||
|
GateBlockChangeSender.updateGateBlocks(gate, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
gate.setLocation(playerLocation);
|
||||||
|
sendMessage(ChatColor.GREEN + "The location of '" + gate.getId() + "' is now at your current location.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendMessage(ChatColor.RED + "There seems to be no frame at your new location! The gate got closed!" + ChatColor.AQUA + " You should build a frame now and execute:");
|
||||||
|
sendMessage(new CommandTriggerOpen().getUsageTemplate(true));
|
||||||
|
} finally {
|
||||||
|
gatesManager.handleGateLocationChange(gate, oldLocation, oldGateBlockLocations, oldFrameBlocks);
|
||||||
|
GateBlockChangeSender.updateGateBlocks(gate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.models.GateMaterial;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
|
||||||
|
public class CommandMaterial extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandMaterial() {
|
||||||
|
aliases.add("material");
|
||||||
|
aliases.add("m");
|
||||||
|
|
||||||
|
requiredParameters.add("id");
|
||||||
|
requiredParameters.add("material");
|
||||||
|
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
hasGateParam = true;
|
||||||
|
helpDescription = "Change the material of a gate";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
GateMaterial material;
|
||||||
|
try {
|
||||||
|
material = new GateMaterial(parameters.get(1));
|
||||||
|
} catch (InvalidParameterException e) {
|
||||||
|
sendMessage(ChatColor.RED + "Invalid material!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
gate.setMaterial(material);
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendMessage(ChatColor.RED + "Frame invalid. Gate is now closed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
GateBlockChangeSender.updateGateBlocks(gate);
|
||||||
|
sendMessage(ChatColor.GREEN + "Gate " + gate.getId() + " uses now " + material.toString() + " as material.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import de.craftinc.gates.util.TextUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class CommandNearby extends BaseLocationCommand {
|
||||||
|
|
||||||
|
public CommandNearby() {
|
||||||
|
aliases.add("nearby");
|
||||||
|
aliases.add("nb");
|
||||||
|
|
||||||
|
helpDescription = "Highlight nearby gates";
|
||||||
|
requiredPermission = PermissionController.permissionInfo;
|
||||||
|
needsPermissionAtCurrentLocation = true;
|
||||||
|
shouldPersistToDisk = false;
|
||||||
|
senderMustBePlayer = true;
|
||||||
|
hasGateParam = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
Set<Gate> nearbyGates = gatesManager.getNearbyGates(player.getLocation().getChunk());
|
||||||
|
|
||||||
|
if (nearbyGates == null) {
|
||||||
|
player.sendMessage("There are no gates near you!");
|
||||||
|
} else {
|
||||||
|
GateBlockChangeSender.temporaryHighlightGatesFrames(player, nearbyGates);
|
||||||
|
|
||||||
|
ArrayList<String> gateNames = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Gate g : nearbyGates) {
|
||||||
|
gateNames.add(g.getId());
|
||||||
|
}
|
||||||
|
player.sendMessage("Nearby gates: " + TextUtil.implode(gateNames, ", "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
|
||||||
|
public class CommandNew extends BaseLocationCommand {
|
||||||
|
|
||||||
|
public CommandNew() {
|
||||||
|
aliases.add("new");
|
||||||
|
aliases.add("create");
|
||||||
|
aliases.add("n");
|
||||||
|
|
||||||
|
requiredParameters.add("id");
|
||||||
|
|
||||||
|
senderMustBePlayer = true;
|
||||||
|
hasGateParam = false;
|
||||||
|
helpDescription = "Create a gate at your current location.";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
needsPermissionAtCurrentLocation = true;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
senderMustBePlayer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
String id = parameters.get(0);
|
||||||
|
|
||||||
|
if (gatesManager.gateExists(id)) {
|
||||||
|
sendMessage(ChatColor.RED + "Creating the gate failed! " + "A gate with the supplied id already exists!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gate = new Gate(id);
|
||||||
|
sendMessage(ChatColor.GREEN + "Gate with id '" + id + "' was created.");
|
||||||
|
|
||||||
|
Location playerLocation = getValidPlayerLocation();
|
||||||
|
|
||||||
|
if (playerLocation != null) {
|
||||||
|
try {
|
||||||
|
gate.setLocation(playerLocation);
|
||||||
|
sendMessage(ChatColor.AQUA + "The gates location has been set to your current location.");
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendMessage(ChatColor.RED + "Your location is invalid!" + ChatColor.AQUA + "Go somewhere else and execute:");
|
||||||
|
sendMessage(new CommandLocation().getUsageTemplate(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
gatesManager.handleNewGate(gate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
public class CommandRemove extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandRemove() {
|
||||||
|
aliases.add("delete");
|
||||||
|
aliases.add("del");
|
||||||
|
aliases.add("remove");
|
||||||
|
|
||||||
|
requiredParameters.add("id");
|
||||||
|
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
helpDescription = "Removes the gate from the game.";
|
||||||
|
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
gatesManager.handleDeletion(gate);
|
||||||
|
GateBlockChangeSender.updateGateBlocks(gate, true);
|
||||||
|
sendMessage(ChatColor.GREEN + "Gate with id '" + gate.getId() + "' was deleted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
public class CommandRename extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandRename() {
|
||||||
|
aliases.add("rename");
|
||||||
|
aliases.add("rn");
|
||||||
|
|
||||||
|
hasGateParam = true;
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
requiredParameters.add("current name");
|
||||||
|
requiredParameters.add("new name");
|
||||||
|
helpDescription = "Changes the id of a gate.";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
String newId = parameters.get(1);
|
||||||
|
|
||||||
|
if (gatesManager.gateExists(newId)) {
|
||||||
|
sendMessage(ChatColor.RED + "Cannot rename " + gate.getId() + ". There is already a gate named " + newId + ".");
|
||||||
|
} else {
|
||||||
|
String oldId = gate.getId();
|
||||||
|
|
||||||
|
gate.setId(newId);
|
||||||
|
gatesManager.handleGateIdChange(gate, oldId);
|
||||||
|
|
||||||
|
sendMessage(ChatColor.GREEN + "Gate " + gate.getId() + " is now known as " + newId + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
|
||||||
|
public class CommandTeleport extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandTeleport() {
|
||||||
|
aliases.add("teleport");
|
||||||
|
aliases.add("t");
|
||||||
|
|
||||||
|
requiredParameters.add("id");
|
||||||
|
|
||||||
|
senderMustBePlayer = true;
|
||||||
|
hasGateParam = true;
|
||||||
|
helpDescription = "Teleport to the location of a gate";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
public class CommandTriggerOpen extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandTriggerOpen() {
|
||||||
|
aliases.add("triggerOpen");
|
||||||
|
aliases.add("o");
|
||||||
|
|
||||||
|
requiredParameters.add("id");
|
||||||
|
helpDescription = "Open/close a gate.";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform() {
|
||||||
|
try {
|
||||||
|
if (!gate.isOpen() && gate.getExit() == null && player != null) {
|
||||||
|
gate.setExit(player.getLocation());
|
||||||
|
sendMessage(ChatColor.GREEN + "The exit of gate '" + gate.getId() + "' is now where you stand.");
|
||||||
|
}
|
||||||
|
|
||||||
|
gate.setOpen(!gate.isOpen());
|
||||||
|
|
||||||
|
GateBlockChangeSender.updateGateBlocks(gate);
|
||||||
|
gatesManager.handleGateLocationChange(gate, null, null, null);
|
||||||
|
sendMessage(ChatColor.GREEN + "The gate is now " + (gate.isOpen() ? "open." : "closed."));
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendMessage(ChatColor.RED + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.commands;
|
||||||
|
|
||||||
|
import de.craftinc.gates.controllers.PermissionController;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
public class CommandTriggerVehicles extends BaseCommand {
|
||||||
|
|
||||||
|
public CommandTriggerVehicles() {
|
||||||
|
aliases.add("vehicles");
|
||||||
|
aliases.add("v");
|
||||||
|
|
||||||
|
requiredParameters.add("id");
|
||||||
|
|
||||||
|
helpDescription = "Allow/deny players to travel while riding.";
|
||||||
|
requiredPermission = PermissionController.permissionManage;
|
||||||
|
needsPermissionAtCurrentLocation = false;
|
||||||
|
shouldPersistToDisk = true;
|
||||||
|
senderMustBePlayer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void perform() {
|
||||||
|
gate.setAllowsVehicles(gate.getAllowsVehicles());
|
||||||
|
|
||||||
|
if (gate.getAllowsVehicles()) {
|
||||||
|
sendMessage(ChatColor.GREEN + "Traveling while riding is now enabled for this gate.");
|
||||||
|
} else {
|
||||||
|
sendMessage(ChatColor.GREEN + "Traveling while riding is now disabled for this gate.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,477 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.controllers;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.persistence.MigrationUtil;
|
||||||
|
import de.craftinc.gates.util.ConfigurationUtil;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.SimpleChunk;
|
||||||
|
import de.craftinc.gates.models.SimpleLocation;
|
||||||
|
|
||||||
|
public class GatesManager {
|
||||||
|
protected List<Gate> gates;
|
||||||
|
|
||||||
|
private static final String gatesPath = "gates"; // path to gates inside the yaml file
|
||||||
|
private static final String storageVersionPath = "version";
|
||||||
|
private static final int storageVersion = 3;
|
||||||
|
|
||||||
|
private File gatesConfigFile;
|
||||||
|
private FileConfiguration gatesConfig;
|
||||||
|
private int chunkRadius;
|
||||||
|
private Map<String, Gate> gatesById;
|
||||||
|
private Map<SimpleChunk, Set<Gate>> gatesByChunk;
|
||||||
|
private Map<SimpleLocation, Gate> gatesByLocation;
|
||||||
|
private Map<SimpleLocation, Gate> gatesByFrameLocation;
|
||||||
|
private boolean storageFileIsInvalid = false;
|
||||||
|
|
||||||
|
public Gate getGateWithId(final String id) {
|
||||||
|
return gatesById.get(id.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Gate> getNearbyGates(final Chunk chunk) {
|
||||||
|
SimpleChunk simpleChunk = new SimpleChunk(chunk);
|
||||||
|
return gatesByChunk.get(simpleChunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the closest gate.
|
||||||
|
*
|
||||||
|
* @param location The location at which to look for a gate.
|
||||||
|
* @return Might return null if there are no nearby gates.
|
||||||
|
*/
|
||||||
|
public Gate getNearestGate(final Location location) {
|
||||||
|
Set<Gate> nearbyGates = getNearbyGates(location.getChunk());
|
||||||
|
|
||||||
|
if (nearbyGates == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double minDist = Double.MAX_VALUE;
|
||||||
|
Gate nearestGate = null;
|
||||||
|
|
||||||
|
for (Gate g : nearbyGates) {
|
||||||
|
double dist = location.distance(g.getLocation());
|
||||||
|
|
||||||
|
if (dist < minDist) {
|
||||||
|
minDist = dist;
|
||||||
|
nearestGate = g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nearestGate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gate getGateAtLocation(final Location location) {
|
||||||
|
SimpleLocation simpleLocation = new SimpleLocation(location);
|
||||||
|
return gatesByLocation.get(simpleLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gate getGateAtFrameLocation(final Location location) {
|
||||||
|
SimpleLocation simpleLocation = new SimpleLocation(location);
|
||||||
|
return gatesByFrameLocation.get(simpleLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveGatesToDisk() {
|
||||||
|
if (storageFileIsInvalid) {
|
||||||
|
Plugin.log(Level.SEVERE, "ERROR: Not saving gates to disk. Storage file is invalid or corrupted!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gatesConfig.set(gatesPath, gates);
|
||||||
|
gatesConfig.set(storageVersionPath, storageVersion);
|
||||||
|
|
||||||
|
try {
|
||||||
|
gatesConfig.save(gatesConfigFile);
|
||||||
|
Plugin.log("Saved gates to disk.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Plugin.log(Level.SEVERE, "ERROR: Could not save gates to disk.");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public boolean loadGatesFromDisk() {
|
||||||
|
// TODO: refactor: move loading/saving logic into persistence package
|
||||||
|
|
||||||
|
this.gatesConfigFile = new File(Plugin.getPlugin().getDataFolder(), "gates.yml");
|
||||||
|
|
||||||
|
if (!this.gatesConfigFile.exists()) {
|
||||||
|
try {
|
||||||
|
boolean isNew = this.gatesConfigFile.createNewFile();
|
||||||
|
|
||||||
|
if (isNew) {
|
||||||
|
Plugin.log(Level.FINEST, "Created gate storage file.");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
this.storageFileIsInvalid = true;
|
||||||
|
Plugin.log(Level.SEVERE, "Cannot create gate storage file! No gates will be persisted.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gatesConfig = new YamlConfiguration();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.gatesConfig.load(this.gatesConfigFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.storageFileIsInvalid = true;
|
||||||
|
Plugin.log(Level.SEVERE, "Gate file on disk is invalid. No gates loaded. Plugin will be disabled! (" + Arrays.toString(e.getStackTrace()) + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gates = (List<Gate>) gatesConfig.getList(gatesPath);
|
||||||
|
|
||||||
|
if (this.gates == null) {
|
||||||
|
this.gates = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object o : this.gates) {
|
||||||
|
|
||||||
|
if (!(o instanceof Gate)) {
|
||||||
|
this.storageFileIsInvalid = true;
|
||||||
|
Plugin.log(Level.SEVERE, "Gate file on disk is invalid. No gates loaded. Plugin will be disabled! (Invalid gate class detected)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Gate g : this.gates) {
|
||||||
|
try {
|
||||||
|
g.validate();
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
g.setOpen(false);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin.log(Level.FINER, "closed gate '" + g.getId() + "' reason: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fillGatesById();
|
||||||
|
fillGatesByChunk();
|
||||||
|
fillGatesByLocation();
|
||||||
|
fillGatesByFrameLocation();
|
||||||
|
|
||||||
|
Plugin.log("Loaded " + this.gates.size() + " gates.");
|
||||||
|
|
||||||
|
// migration
|
||||||
|
int fileStorageVersion = gatesConfig.getInt(storageVersionPath);
|
||||||
|
|
||||||
|
if (fileStorageVersion > storageVersion) {
|
||||||
|
this.storageFileIsInvalid = true;
|
||||||
|
Plugin.log(Level.SEVERE, "Unsupported storage version detected! Make sure you have the latest version of Craft Inc. Gates installed. Plugin will be disabled!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileStorageVersion < storageVersion && !this.gates.isEmpty()) {
|
||||||
|
Plugin.log("Outdated storage version detected. Performing data migration...");
|
||||||
|
boolean success = MigrationUtil.performMigration(fileStorageVersion, storageVersion, this.gates);
|
||||||
|
|
||||||
|
this.storageFileIsInvalid = !success;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getChunkRadius() {
|
||||||
|
if (this.chunkRadius == 0) {
|
||||||
|
this.chunkRadius = Plugin.getPlugin().getConfig().getInt(ConfigurationUtil.confPlayerGateBlockUpdateRadiusKey);
|
||||||
|
this.chunkRadius = this.chunkRadius >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.chunkRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillGatesById() {
|
||||||
|
gatesById = new HashMap<>((int) (gates.size() * 1.25));
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
this.addGateWithId(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillGatesByChunk() {
|
||||||
|
HashSet<SimpleChunk> chunksUsedByGates = new HashSet<>();
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
if (g.getLocation() != null) {
|
||||||
|
Chunk c = g.getLocation().getChunk();
|
||||||
|
|
||||||
|
int x = c.getX();
|
||||||
|
int z = c.getZ();
|
||||||
|
|
||||||
|
for (int i = x - getChunkRadius(); i < x + getChunkRadius(); i++) {
|
||||||
|
for (int j = z - getChunkRadius(); j < z + getChunkRadius(); j++) {
|
||||||
|
chunksUsedByGates.add(new SimpleChunk(i, j, c.getWorld()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gatesByChunk = new HashMap<>((int) (chunksUsedByGates.size() * 1.25));
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
this.addGateByChunk(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillGatesByLocation() {
|
||||||
|
Set<Location> gateBlocks = new HashSet<>();
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
for (Location l : g.getGateBlockLocations()) {
|
||||||
|
gateBlocks.add(l);
|
||||||
|
Location headLocation = l.clone().add(0, 1, 0);
|
||||||
|
gateBlocks.add(headLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gatesByLocation = new HashMap<>((int) (gateBlocks.size() * 1.25));
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
this.addGateByLocations(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillGatesByFrameLocation() {
|
||||||
|
int numFrameBlocks = 0;
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
numFrameBlocks += g.getGateFrameBlocks().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
gatesByFrameLocation = new HashMap<>((int) (numFrameBlocks * 1.25));
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
this.addGateByFrameLocations(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeGateById(final String id) {
|
||||||
|
gatesById.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addGateWithId(final Gate g) {
|
||||||
|
gatesById.put(g.getId(), g);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeGateByLocation(final Set<Location> gateBlocks) {
|
||||||
|
if (gateBlocks != null) {
|
||||||
|
|
||||||
|
for (Location l : gateBlocks) {
|
||||||
|
SimpleLocation sl = new SimpleLocation(l);
|
||||||
|
gatesByLocation.remove(sl);
|
||||||
|
|
||||||
|
SimpleLocation headLocation = new SimpleLocation(l, true);
|
||||||
|
gatesByLocation.remove(headLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeGateByFrameLocation(final Set<Block> gateFrameBlocks) {
|
||||||
|
if (gateFrameBlocks != null) {
|
||||||
|
|
||||||
|
for (Block block : gateFrameBlocks) {
|
||||||
|
SimpleLocation sl = new SimpleLocation(block.getLocation());
|
||||||
|
gatesByFrameLocation.remove(sl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addGateByLocations(final Gate g) {
|
||||||
|
for (Location l : g.getGateBlockLocations()) {
|
||||||
|
SimpleLocation sl = new SimpleLocation(l);
|
||||||
|
gatesByLocation.put(sl, g);
|
||||||
|
|
||||||
|
SimpleLocation headLocation = new SimpleLocation(l, true);
|
||||||
|
gatesByLocation.put(headLocation, g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addGateByFrameLocations(final Gate g) {
|
||||||
|
for (Block block : g.getGateFrameBlocks()) {
|
||||||
|
SimpleLocation sl = new SimpleLocation(block.getLocation());
|
||||||
|
gatesByFrameLocation.put(sl, g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeGateFromChunk(final Gate g, final Location l) {
|
||||||
|
if (l != null) {
|
||||||
|
|
||||||
|
Chunk c = l.getChunk();
|
||||||
|
int x = c.getX();
|
||||||
|
int z = c.getZ();
|
||||||
|
|
||||||
|
for (int i = x - getChunkRadius(); i < x + getChunkRadius(); i++) {
|
||||||
|
|
||||||
|
for (int j = z - getChunkRadius(); j < z + getChunkRadius(); j++) {
|
||||||
|
|
||||||
|
SimpleChunk sc = new SimpleChunk(i, j, c.getWorld());
|
||||||
|
Set<Gate> gatesInChunk = gatesByChunk.get(sc);
|
||||||
|
|
||||||
|
if (gatesInChunk != null) {
|
||||||
|
gatesInChunk.remove(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addGateByChunk(final Gate g) {
|
||||||
|
Location gateLocation = g.getLocation();
|
||||||
|
|
||||||
|
if (gateLocation != null) {
|
||||||
|
|
||||||
|
Chunk c = g.getLocation().getChunk();
|
||||||
|
int x = c.getX();
|
||||||
|
int z = c.getZ();
|
||||||
|
|
||||||
|
for (int i = x - getChunkRadius(); i < x + getChunkRadius(); i++) {
|
||||||
|
|
||||||
|
for (int j = z - getChunkRadius(); j < z + getChunkRadius(); j++) {
|
||||||
|
|
||||||
|
SimpleChunk sc = new SimpleChunk(i, j, c.getWorld());
|
||||||
|
|
||||||
|
Set<Gate> gatesForC = gatesByChunk.get(sc);
|
||||||
|
|
||||||
|
if (gatesForC == null) {
|
||||||
|
gatesForC = new HashSet<>(); // NOTE: not optimizing size here
|
||||||
|
gatesByChunk.put(sc, gatesForC);
|
||||||
|
}
|
||||||
|
|
||||||
|
gatesForC.add(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void storeInvalidGate(Map<String, Object> map) {
|
||||||
|
File invalidGatesFile = new File(Plugin.getPlugin().getDataFolder(), "invalid_gates.yml");
|
||||||
|
Boolean invalidGatesFileExists = invalidGatesFile.exists();
|
||||||
|
|
||||||
|
try {
|
||||||
|
FileWriter fileWriter = new FileWriter(invalidGatesFile, true);
|
||||||
|
|
||||||
|
if (!invalidGatesFileExists) {
|
||||||
|
fileWriter.write("gates:\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fileWriter.write("- ==: ");
|
||||||
|
fileWriter.write(map.get("==").toString() + "\n");
|
||||||
|
map.remove("==");
|
||||||
|
|
||||||
|
fileWriter.write("\topen: false\n");
|
||||||
|
map.remove("open");
|
||||||
|
|
||||||
|
fileWriter.write("\tgateBlocks: []\n");
|
||||||
|
map.remove("gateBlocks");
|
||||||
|
|
||||||
|
|
||||||
|
for (String key : map.keySet()) {
|
||||||
|
Object value = map.get(key);
|
||||||
|
|
||||||
|
fileWriter.write("\t" + key + ": ");
|
||||||
|
|
||||||
|
if (value instanceof Map) {
|
||||||
|
fileWriter.write("\n");
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> valueMap = (Map<String, Object>) value;
|
||||||
|
|
||||||
|
for (String k : valueMap.keySet()) {
|
||||||
|
Object v = valueMap.get(k);
|
||||||
|
|
||||||
|
fileWriter.write("\t\t" + k + ": " + v.toString() + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fileWriter.write(value.toString() + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileWriter.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Plugin.log("ERROR: Could not save invalid gates to disk. Reason: \n" + Arrays.toString(e.getStackTrace()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleGateIdChange(final Gate g, final String oldId) {
|
||||||
|
this.removeGateById(oldId);
|
||||||
|
this.addGateWithId(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleGateLocationChange(final Gate g,
|
||||||
|
final Location oldLocation,
|
||||||
|
final Set<Location> oldGateBlockLocations,
|
||||||
|
final Set<Block> oldGateFrameBlocks) {
|
||||||
|
this.removeGateFromChunk(g, oldLocation);
|
||||||
|
this.addGateByChunk(g);
|
||||||
|
|
||||||
|
this.removeGateByLocation(oldGateBlockLocations);
|
||||||
|
this.addGateByLocations(g);
|
||||||
|
|
||||||
|
this.removeGateByFrameLocation(oldGateFrameBlocks);
|
||||||
|
this.addGateByFrameLocations(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleGateExitChange(final Gate g, final Location oldExit) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleNewGate(final Gate g) {
|
||||||
|
this.gates.add(g);
|
||||||
|
|
||||||
|
this.addGateByChunk(g);
|
||||||
|
this.addGateByLocations(g);
|
||||||
|
this.addGateWithId(g);
|
||||||
|
this.addGateByFrameLocations(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleDeletion(final Gate g) {
|
||||||
|
this.gates.remove(g);
|
||||||
|
|
||||||
|
this.removeGateById(g.getId());
|
||||||
|
this.removeGateFromChunk(g, g.getLocation());
|
||||||
|
this.removeGateByLocation(g.getGateBlockLocations());
|
||||||
|
this.removeGateByFrameLocation(g.getGateFrameBlocks());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean gateExists(final String id) {
|
||||||
|
return gatesById.containsKey(id.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Gate> allGates() {
|
||||||
|
return gates;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package de.craftinc.gates.controllers;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import net.milkbowl.vault.permission.Permission;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
public class PermissionController {
|
||||||
|
public static final String permissionInfo = "craftincgates.info";
|
||||||
|
public static final String permissionManage = "craftincgates.manage";
|
||||||
|
public static final String permissionUse = "craftincgates.use";
|
||||||
|
|
||||||
|
private Permission permission;
|
||||||
|
|
||||||
|
public void setPermission(Permission permission) {
|
||||||
|
this.permission = permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(CommandSender sender, Gate gate, String permission) {
|
||||||
|
assert(sender != null);
|
||||||
|
assert(permission != null);
|
||||||
|
|
||||||
|
if (gate == null) {
|
||||||
|
return hasPermission(sender, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Location location = gate.getLocation();
|
||||||
|
final Location exit = gate.getExit();
|
||||||
|
|
||||||
|
boolean permAtLocation = location == null || hasPermission(sender, location.getWorld(), permission);
|
||||||
|
boolean permAtExit = exit == null || hasPermission(sender, exit.getWorld(), permission);
|
||||||
|
|
||||||
|
return permAtLocation && permAtExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(CommandSender sender, String permission) {
|
||||||
|
return hasPermission(sender, (World)null, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasPermission(CommandSender sender, World world, String permission) {
|
||||||
|
assert(sender != null);
|
||||||
|
assert(permission != null);
|
||||||
|
|
||||||
|
if (this.permission == null) {
|
||||||
|
// fallback - use the standard bukkit permission system
|
||||||
|
return sender.hasPermission(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(sender instanceof OfflinePlayer)) {
|
||||||
|
return this.permission.has(sender, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
String worldName = world != null ? world.getName() : null;
|
||||||
|
return this.permission.playerHas(worldName, (OfflinePlayer)sender, permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package de.craftinc.gates.controllers;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.util.ConfigurationUtil;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class TeleportController {
|
||||||
|
private TeleportMessageUtil messageUtil;
|
||||||
|
private GatesManager gatesManager;
|
||||||
|
private PermissionController permissionController;
|
||||||
|
|
||||||
|
public TeleportController(Plugin plugin) {
|
||||||
|
this.gatesManager = plugin.getGatesManager();
|
||||||
|
this.messageUtil = new TeleportMessageUtil(plugin.getConfig());
|
||||||
|
this.permissionController = plugin.getPermissionController();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try teleporting a player at given location.
|
||||||
|
*/
|
||||||
|
public void teleport(final Player player, Location toLocation) {
|
||||||
|
final Gate gateAtLocation = gatesManager.getGateAtLocation(toLocation);
|
||||||
|
|
||||||
|
if ((gateAtLocation == null) || !gateAtLocation.isOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!permissionController.hasPermission(player, gateAtLocation, PermissionController.permissionUse)) {
|
||||||
|
messageUtil.sendNoPermissionMessage(player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.teleportPlayer(player, gateAtLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void teleportPlayer(final Player player, final Gate gate) {
|
||||||
|
final Entity vehicle = player.getVehicle();
|
||||||
|
|
||||||
|
if (vehicle != null && !gate.getAllowsVehicles()) {
|
||||||
|
messageUtil.sendVehicleForbiddenMessage(player);
|
||||||
|
Plugin.log("no vehicle transport");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Location destination = calculateDestination(player, gate);
|
||||||
|
player.teleport(destination);
|
||||||
|
|
||||||
|
if (vehicle != null) {
|
||||||
|
vehicle.teleport(destination, PlayerTeleportEvent.TeleportCause.PLUGIN);
|
||||||
|
vehicle.setPassenger(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
messageUtil.sendTeleportMessage(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Location calculateDestination(Player player, Gate gate) {
|
||||||
|
final Location exit = gate.getExit();
|
||||||
|
final Location pLocation = player.getLocation();
|
||||||
|
final Float newYaw = exit.getYaw() - gate.getLocation().getYaw() + pLocation.getYaw();
|
||||||
|
|
||||||
|
return new Location(exit.getWorld(),
|
||||||
|
exit.getX(),
|
||||||
|
exit.getY(),
|
||||||
|
exit.getZ(),
|
||||||
|
newYaw,
|
||||||
|
pLocation.getPitch()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TeleportMessageUtil {
|
||||||
|
private HashMap<String, Long> lastNoPermissionMessages = new HashMap<>();
|
||||||
|
private FileConfiguration config;
|
||||||
|
|
||||||
|
TeleportMessageUtil(FileConfiguration config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendVehicleForbiddenMessage(Player player) {
|
||||||
|
if (!config.getBoolean(ConfigurationUtil.confShowTeleportNoPermissionMessageKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String notAllowedMessage = config.getString(ConfigurationUtil.confGateTeleportVehicleNotAllowedMessageKey);
|
||||||
|
player.sendMessage(ChatColor.DARK_AQUA + notAllowedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendNoPermissionMessage(Player player) {
|
||||||
|
if (!config.getBoolean(ConfigurationUtil.confShowTeleportNoPermissionMessageKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String playerName = player.getPlayer().getName();
|
||||||
|
|
||||||
|
if (playerName == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Long now = Calendar.getInstance().getTimeInMillis();
|
||||||
|
|
||||||
|
// do not display messages more often than once per second
|
||||||
|
if (!this.lastNoPermissionMessages.containsKey(playerName)
|
||||||
|
|| this.lastNoPermissionMessages.get(playerName) < now - 10000L) {
|
||||||
|
|
||||||
|
final String noPermissionString = config.getString(ConfigurationUtil.confGateTeleportNoPermissionMessageKey);
|
||||||
|
player.sendMessage(ChatColor.RED + noPermissionString);
|
||||||
|
this.lastNoPermissionMessages.put(playerName, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendTeleportMessage(Player player) {
|
||||||
|
if (!config.getBoolean(ConfigurationUtil.confShowTeleportMessageKey)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String teleportMessage = config.getString(ConfigurationUtil.confGateTeleportMessageKey);
|
||||||
|
player.sendMessage(ChatColor.DARK_AQUA + teleportMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.listeners;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
|
||||||
|
public class BlockBreakListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gate gate = Plugin.getPlugin().getGatesManager().getGateAtFrameLocation(event.getBlock().getLocation());
|
||||||
|
|
||||||
|
if (gate != null && gate.getMaterial().getMaterial() != Material.AIR) {
|
||||||
|
try {
|
||||||
|
gate.setOpen(false);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
|
GateBlockChangeSender.updateGateBlocks(gate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.listeners;
|
||||||
|
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||||
|
|
||||||
|
public class PlayerChangedWorldListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
|
public void onPlayerChangeWorld(PlayerChangedWorldEvent event) {
|
||||||
|
Player p = event.getPlayer();
|
||||||
|
GateBlockChangeSender.updateGateBlocks(p, p.getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.listeners;
|
||||||
|
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
public class PlayerJoinListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
Player p = event.getPlayer();
|
||||||
|
GateBlockChangeSender.updateGateBlocks(p, p.getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.listeners;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.controllers.TeleportController;
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
|
||||||
|
public class PlayerMoveListener implements Listener {
|
||||||
|
private TeleportController teleportController;
|
||||||
|
|
||||||
|
public PlayerMoveListener(Plugin plugin) {
|
||||||
|
this.teleportController = new TeleportController(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getFrom().getChunk() != event.getTo().getChunk()) {
|
||||||
|
GateBlockChangeSender.updateGateBlocks(event.getPlayer(), event.getTo());
|
||||||
|
}
|
||||||
|
|
||||||
|
teleportController.teleport(event.getPlayer(), event.getTo());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.listeners;
|
||||||
|
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||||
|
|
||||||
|
public class PlayerRespawnListener implements Listener {
|
||||||
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
|
public void onPlayerRespawn(PlayerRespawnEvent event) {
|
||||||
|
GateBlockChangeSender.updateGateBlocks(event.getPlayer(), event.getRespawnLocation(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.listeners;
|
||||||
|
|
||||||
|
import de.craftinc.gates.util.GateBlockChangeSender;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
|
|
||||||
|
public class PlayerTeleportListener implements Listener {
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
|
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GateBlockChangeSender.updateGateBlocks(event.getPlayer(), event.getTo(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package de.craftinc.gates.listeners;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.controllers.TeleportController;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.vehicle.VehicleMoveEvent;
|
||||||
|
|
||||||
|
public class VehicleMoveListener implements Listener {
|
||||||
|
private TeleportController teleportController;
|
||||||
|
|
||||||
|
public VehicleMoveListener(Plugin plugin) {
|
||||||
|
this.teleportController = new TeleportController(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
|
public void onVehicleMove(VehicleMoveEvent event) {
|
||||||
|
Entity passenger = event.getVehicle().getPassenger();
|
||||||
|
|
||||||
|
if (passenger instanceof Player) {
|
||||||
|
teleportController.teleport((Player)passenger, event.getTo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.models;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.util.ConfigurationUtil;
|
||||||
|
import de.craftinc.gates.util.FloodUtil;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
public class Gate implements ConfigurationSerializable {
|
||||||
|
private Location location; /* saving both location and gateBlockLocations is redundant but makes it easy to allow players to reshape gates */
|
||||||
|
private Set<Location> gateBlockLocations = new HashSet<>(); /* Locations of the blocks inside the gate */
|
||||||
|
private Set<Block> gateFrameBlocks = new HashSet<>();
|
||||||
|
private Location exit;
|
||||||
|
private boolean isOpen = false;
|
||||||
|
private boolean allowsVehicles = true;
|
||||||
|
private String id;
|
||||||
|
private GateMaterial material = new GateMaterial(Material.PORTAL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You should never create two gates with the same 'id'. Also see 'setId(String id)'.
|
||||||
|
*
|
||||||
|
* @param id This parameter must not be 'null'. An exception will be thrown otherwise!
|
||||||
|
*/
|
||||||
|
public Gate(final String id) {
|
||||||
|
setId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " " + this.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GateDirection getDirection() {
|
||||||
|
if (gateBlockLocations.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
Block some = ((Location)gateBlockLocations.toArray()[0]).getBlock();
|
||||||
|
boolean east = gateBlockLocations.contains(some.getRelative(BlockFace.EAST).getLocation());
|
||||||
|
boolean west = gateBlockLocations.contains(some.getRelative(BlockFace.WEST).getLocation());
|
||||||
|
|
||||||
|
return east || west ? GateDirection.EastWest : GateDirection.NorthSouth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GateMaterial getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaterial(GateMaterial material) throws Exception {
|
||||||
|
this.material = material;
|
||||||
|
validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return This method might return a 'null' data.
|
||||||
|
*/
|
||||||
|
public Location getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param location Supplying 'null' is permitted.
|
||||||
|
* @throws Exception Will throw an exception if the gate is open and an invalid (no gate frame) location is
|
||||||
|
* supplied. Note that the supplied 'location' will be set even if an exception is thrown. Note that this
|
||||||
|
* gate will be closed if an exception is thrown.
|
||||||
|
*/
|
||||||
|
public void setLocation(final Location location) throws Exception {
|
||||||
|
this.location = location;
|
||||||
|
|
||||||
|
if (isOpen) {
|
||||||
|
findPortalBlocks();
|
||||||
|
validate();
|
||||||
|
} else {
|
||||||
|
this.gateBlockLocations = new HashSet<>();
|
||||||
|
this.gateFrameBlocks = new HashSet<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return This method might return a 'null' value.
|
||||||
|
*/
|
||||||
|
public Location getExit() {
|
||||||
|
return exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param exit Supplying 'null' is permitted.
|
||||||
|
* @throws Exception An exception will be thrown if 'null' data is supplied and this gate is open. Note that the
|
||||||
|
* supplied 'exit' will be set even if an exception is thrown. Note that this gate will be closed if an
|
||||||
|
* exception is thrown.
|
||||||
|
*/
|
||||||
|
public void setExit(final Location exit) throws Exception {
|
||||||
|
this.exit = exit;
|
||||||
|
validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return This method will never return 'null'.
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every gate should have an unique 'id'. You should therefore check if another gate with the same 'id' exists.
|
||||||
|
* Note that this method will not check if another gate with the same 'id' exists!
|
||||||
|
*
|
||||||
|
* @param id This parameter must not be 'null'. An exception will be thrown otherwise!
|
||||||
|
*/
|
||||||
|
public void setId(final String id) {
|
||||||
|
if (id == null) {
|
||||||
|
throw new IllegalArgumentException("gate 'id' cannot be 'null'");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.id = id.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOpen() {
|
||||||
|
return isOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOpen(boolean isOpen) throws Exception {
|
||||||
|
if (isOpen && !this.isOpen) {
|
||||||
|
findPortalBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isOpen = isOpen;
|
||||||
|
validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowsVehicles(boolean allowsVehicles) {
|
||||||
|
this.allowsVehicles = allowsVehicles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getAllowsVehicles() {
|
||||||
|
return this.allowsVehicles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Will never return 'null' but might return an empty Set.
|
||||||
|
*/
|
||||||
|
public Set<Location> getGateBlockLocations() {
|
||||||
|
return gateBlockLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Will never return 'null' but might return an empty Set.
|
||||||
|
*/
|
||||||
|
public Set<Block> getGateFrameBlocks() {
|
||||||
|
return gateFrameBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findPortalBlocks() {
|
||||||
|
gateBlockLocations = new HashSet<>();
|
||||||
|
Set<Block> gateBlocks = FloodUtil.getGatePortalBlocks(location.getBlock());
|
||||||
|
|
||||||
|
if (gateBlocks != null) {
|
||||||
|
for (Block b : gateBlocks) {
|
||||||
|
gateBlockLocations.add(b.getLocation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gateFrameBlocks = FloodUtil.getFrame(gateBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if values attributes do add up; will close gate on wrong values.
|
||||||
|
*/
|
||||||
|
public void validate() throws Exception {
|
||||||
|
if (!isOpen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location == null) {
|
||||||
|
isOpen = false;
|
||||||
|
this.gateBlockLocations = new HashSet<>();
|
||||||
|
this.gateFrameBlocks = new HashSet<>();
|
||||||
|
|
||||||
|
throw new Exception("Gate got closed. It has no location.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exit == null) {
|
||||||
|
isOpen = false;
|
||||||
|
this.gateBlockLocations = new HashSet<>();
|
||||||
|
this.gateFrameBlocks = new HashSet<>();
|
||||||
|
|
||||||
|
throw new Exception("Gate got closed. It has no exit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gateBlockLocations.size() == 0) {
|
||||||
|
isOpen = false;
|
||||||
|
this.gateBlockLocations = new HashSet<>();
|
||||||
|
this.gateFrameBlocks = new HashSet<>();
|
||||||
|
|
||||||
|
throw new Exception("Gate got closed. The frame is missing or broken. (no gate blocks)");
|
||||||
|
}
|
||||||
|
|
||||||
|
validateFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateFrame() throws Exception {
|
||||||
|
boolean isAir = material.getMaterial() == Material.AIR;
|
||||||
|
boolean ignore = !Plugin.getPlugin().getConfig().getBoolean(ConfigurationUtil.confCheckForBrokenGateFramesKey);
|
||||||
|
|
||||||
|
if (isAir || ignore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Block b : gateFrameBlocks) {
|
||||||
|
|
||||||
|
if (b.getType() == Material.AIR) {
|
||||||
|
isOpen = false;
|
||||||
|
this.gateBlockLocations = new HashSet<>();
|
||||||
|
this.gateFrameBlocks = new HashSet<>();
|
||||||
|
|
||||||
|
throw new Exception("Gate got closed. The frame is missing or broken. (missing frame block(s))");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* INTERFACE: ConfigurationSerializable
|
||||||
|
*/
|
||||||
|
static private String idKey = "id";
|
||||||
|
static private String locationKey = "location";
|
||||||
|
static private String gateBlocksKey = "gateBlocks";
|
||||||
|
static private String exitKey = "exit";
|
||||||
|
static private String materialKey = "material";
|
||||||
|
static private String isOpenKey = "open";
|
||||||
|
static private String allowsVehiclesKey = "allowsVehiclesKey";
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Gate(Map<String, Object> map) {
|
||||||
|
try {
|
||||||
|
id = map.get(idKey).toString().toLowerCase();
|
||||||
|
location = (Location) map.get(locationKey);
|
||||||
|
exit = (Location) map.get(exitKey);
|
||||||
|
material = new GateMaterial((String)map.get(materialKey));
|
||||||
|
isOpen = (Boolean) map.get(isOpenKey);
|
||||||
|
allowsVehicles = (Boolean) map.get(allowsVehiclesKey);
|
||||||
|
gateBlockLocations = (Set<Location>) map.get(gateBlocksKey);
|
||||||
|
|
||||||
|
gateFrameBlocks = FloodUtil.getFrameWithLocations(gateBlockLocations);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Plugin.log("ERROR: Failed to load gate '" + id + "'! (" + e.getMessage() + ")");
|
||||||
|
Plugin.log("NOTE: This gate will be removed from 'gates.yml' and added to 'invalid_gates.yml'!");
|
||||||
|
|
||||||
|
Plugin.getPlugin().getGatesManager().storeInvalidGate(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
validate(); // make sure to not write invalid stuff to disk
|
||||||
|
} catch (Exception e) {
|
||||||
|
Plugin.log("The loaded gate " + this.getId() + " seems to be not valid: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> serialize() {
|
||||||
|
Map<String, Object> retVal = new HashMap<>();
|
||||||
|
|
||||||
|
retVal.put(idKey, id);
|
||||||
|
retVal.put(isOpenKey, isOpen);
|
||||||
|
retVal.put(allowsVehiclesKey, allowsVehicles);
|
||||||
|
retVal.put(gateBlocksKey, gateBlockLocations);
|
||||||
|
retVal.put(materialKey, material.toString());
|
||||||
|
|
||||||
|
if (exit != null) {
|
||||||
|
retVal.put(exitKey, exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location != null) {
|
||||||
|
retVal.put(locationKey, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package de.craftinc.gates.models;
|
||||||
|
|
||||||
|
public enum GateDirection {
|
||||||
|
EastWest,
|
||||||
|
NorthSouth
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package de.craftinc.gates.models;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
|
||||||
|
public class GateMaterial {
|
||||||
|
private Material material;
|
||||||
|
|
||||||
|
GateMaterial(Material material) {
|
||||||
|
this.material = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GateMaterial(String materialString) throws InvalidParameterException {
|
||||||
|
Material material;
|
||||||
|
|
||||||
|
switch (materialString) {
|
||||||
|
case "air":
|
||||||
|
material = Material.AIR;
|
||||||
|
break;
|
||||||
|
case "sapling":
|
||||||
|
material = Material.SAPLING;
|
||||||
|
break;
|
||||||
|
case "water":
|
||||||
|
material = Material.STATIONARY_WATER;
|
||||||
|
break;
|
||||||
|
case "lava":
|
||||||
|
material = Material.STATIONARY_LAVA;
|
||||||
|
break;
|
||||||
|
case "cobweb":
|
||||||
|
material = Material.WEB;
|
||||||
|
break;
|
||||||
|
case "grass":
|
||||||
|
material = Material.LONG_GRASS;
|
||||||
|
break;
|
||||||
|
case "dead bush":
|
||||||
|
material = Material.DEAD_BUSH;
|
||||||
|
break;
|
||||||
|
case "dandelion":
|
||||||
|
material = Material.YELLOW_FLOWER;
|
||||||
|
break;
|
||||||
|
case "poppy":
|
||||||
|
material = Material.RED_ROSE;
|
||||||
|
break;
|
||||||
|
case "brown mushroom":
|
||||||
|
material = Material.BROWN_MUSHROOM;
|
||||||
|
break;
|
||||||
|
case "red mushroom":
|
||||||
|
material = Material.RED_MUSHROOM;
|
||||||
|
break;
|
||||||
|
case "torch":
|
||||||
|
material = Material.TORCH;
|
||||||
|
break;
|
||||||
|
case "redstone torch (off)":
|
||||||
|
material = Material.REDSTONE_TORCH_OFF;
|
||||||
|
break;
|
||||||
|
case "redstone torch (on)":
|
||||||
|
material = Material.REDSTONE_TORCH_ON;
|
||||||
|
break;
|
||||||
|
case "fence":
|
||||||
|
material = Material.FENCE;
|
||||||
|
break;
|
||||||
|
case "nether portal":
|
||||||
|
material = Material.PORTAL;
|
||||||
|
break;
|
||||||
|
case "iron bars":
|
||||||
|
material = Material.IRON_FENCE;
|
||||||
|
break;
|
||||||
|
case "glass pane":
|
||||||
|
material = Material.THIN_GLASS;
|
||||||
|
break;
|
||||||
|
case "fence gate":
|
||||||
|
material = Material.FENCE_GATE;
|
||||||
|
break;
|
||||||
|
case "nether brick fence":
|
||||||
|
material = Material.NETHER_FENCE;
|
||||||
|
break;
|
||||||
|
case "nether wart":
|
||||||
|
material = Material.NETHER_WARTS;
|
||||||
|
break;
|
||||||
|
case "end portal":
|
||||||
|
material = Material.ENDER_PORTAL;
|
||||||
|
break;
|
||||||
|
case "cobblestone wall":
|
||||||
|
material = Material.COBBLE_WALL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidParameterException();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.material = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
switch (material) {
|
||||||
|
case AIR:
|
||||||
|
return "air";
|
||||||
|
case SAPLING:
|
||||||
|
return "sapling";
|
||||||
|
case STATIONARY_WATER:
|
||||||
|
return "water";
|
||||||
|
case STATIONARY_LAVA:
|
||||||
|
return "lava";
|
||||||
|
case WEB:
|
||||||
|
return "cobweb";
|
||||||
|
case LONG_GRASS:
|
||||||
|
return "grass";
|
||||||
|
case DEAD_BUSH:
|
||||||
|
return "dead bush";
|
||||||
|
case YELLOW_FLOWER:
|
||||||
|
return "dandelion";
|
||||||
|
case RED_ROSE:
|
||||||
|
return "poppy";
|
||||||
|
case BROWN_MUSHROOM:
|
||||||
|
return "brown mushroom";
|
||||||
|
case RED_MUSHROOM:
|
||||||
|
return "red mushroom";
|
||||||
|
case TORCH:
|
||||||
|
return "torch";
|
||||||
|
case REDSTONE_TORCH_OFF:
|
||||||
|
return "redstone torch (off)";
|
||||||
|
case REDSTONE_TORCH_ON:
|
||||||
|
return "redstone torch (on)";
|
||||||
|
case FENCE:
|
||||||
|
return "fence";
|
||||||
|
case PORTAL:
|
||||||
|
return "nether portal";
|
||||||
|
case IRON_FENCE:
|
||||||
|
return "iron bars";
|
||||||
|
case THIN_GLASS:
|
||||||
|
return "glass pane";
|
||||||
|
case FENCE_GATE:
|
||||||
|
return "fence gate";
|
||||||
|
case NETHER_FENCE:
|
||||||
|
return "nether brick fence";
|
||||||
|
case NETHER_WARTS:
|
||||||
|
return "nether wart";
|
||||||
|
case ENDER_PORTAL:
|
||||||
|
return "end portal";
|
||||||
|
case COBBLE_WALL:
|
||||||
|
return "cobblestone wall";
|
||||||
|
default:
|
||||||
|
return "nether portal";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Material getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getData(GateDirection direction) {
|
||||||
|
switch (material) {
|
||||||
|
case PORTAL:
|
||||||
|
return direction == GateDirection.EastWest ? (byte)0b0 : (byte)0b10;
|
||||||
|
case GRASS:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.models;
|
||||||
|
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
public class SimpleChunk {
|
||||||
|
private int x;
|
||||||
|
private int z;
|
||||||
|
private String world;
|
||||||
|
|
||||||
|
public SimpleChunk(Chunk c) {
|
||||||
|
this.x = c.getX();
|
||||||
|
this.z = c.getZ();
|
||||||
|
this.world = c.getWorld().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SimpleChunk(int x, int z, World w) {
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
this.world = w.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof SimpleChunk) {
|
||||||
|
SimpleChunk otherLocation = (SimpleChunk) o;
|
||||||
|
|
||||||
|
if (otherLocation.x == this.x
|
||||||
|
&& otherLocation.z == this.z
|
||||||
|
&& otherLocation.world.equals(this.world)) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 11;
|
||||||
|
hash = 29 * hash + x;
|
||||||
|
hash = 37 * hash + z;
|
||||||
|
hash = 29 * hash + world.hashCode();
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.getClass().toString() + " (x=" + this.x + " z=" + this.z + " world='" + this.world + "')";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.models;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
|
||||||
|
public class SimpleLocation {
|
||||||
|
private String world;
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
private int z;
|
||||||
|
|
||||||
|
public SimpleLocation(Location l) {
|
||||||
|
this.world = l.getWorld().getName();
|
||||||
|
|
||||||
|
// Using Block coordinates makes it possible to compare block locations with player locations.
|
||||||
|
// There might be an offset of 1 otherwise.
|
||||||
|
this.x = l.getBlockX();
|
||||||
|
this.y = l.getBlockY();
|
||||||
|
this.z = l.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleLocation(Location l, boolean isHeadPosition) {
|
||||||
|
this.world = l.getWorld().getName();
|
||||||
|
|
||||||
|
// Using Block coordinates makes it possible to compare block locations with player locations.
|
||||||
|
// There might be an offset of 1 otherwise.
|
||||||
|
this.x = l.getBlockX();
|
||||||
|
this.y = l.getBlockY();
|
||||||
|
this.z = l.getBlockZ();
|
||||||
|
|
||||||
|
if (isHeadPosition) {
|
||||||
|
this.y--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return super.toString() + " x: " + x + " y: " + y + " z: " + z + " world: " + world;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object o) {
|
||||||
|
if (o instanceof SimpleLocation) {
|
||||||
|
SimpleLocation otherLocation = (SimpleLocation) o;
|
||||||
|
|
||||||
|
if (otherLocation.x == this.x
|
||||||
|
&& otherLocation.y == this.y
|
||||||
|
&& otherLocation.z == this.z
|
||||||
|
&& otherLocation.world.equals(this.world)) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int hash = 13;
|
||||||
|
hash = 37 * hash + x;
|
||||||
|
hash = 31 * hash + y;
|
||||||
|
hash = 37 * hash + z;
|
||||||
|
hash = 31 * hash + world.hashCode();
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.persistence;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
|
||||||
|
public class MigrationUtil {
|
||||||
|
|
||||||
|
public static boolean performMigration(int storageVersion, int currentVersion, List<Gate> gates) {
|
||||||
|
if (storageVersion != currentVersion) {
|
||||||
|
Plugin.log(Level.SEVERE, "Supplied storage version is currently not supported!" +
|
||||||
|
"Make sure you have the latest version of Craft Inc. Gates installed. Plugin will be disabled!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.util;
|
||||||
|
|
||||||
|
public class ConfigurationUtil {
|
||||||
|
public static final String confMaxGateBlocksKey = "maxGateBlocks";
|
||||||
|
public static final String confPlayerGateBlockUpdateRadiusKey = "playerGateBlockUpdateRadius";
|
||||||
|
public static final String confCheckForBrokenGateFramesKey = "checkForBrokenGateFrames";
|
||||||
|
public static final String confGateTeleportMessageKey = "gateTeleportMessage";
|
||||||
|
public static final String confGateTeleportVehicleNotAllowedMessageKey = "gateTeleportVehicleNotAllowedMessage";
|
||||||
|
public static final String confShowTeleportMessageKey = "showTeleportMessage";
|
||||||
|
public static final String confGateTeleportNoPermissionMessageKey = "gateTeleportNoPermissionMessage";
|
||||||
|
public static final String confShowTeleportNoPermissionMessageKey = "showTeleportNoPermissionMessage";
|
||||||
|
public static final String confSaveOnChangesKey = "saveOnChanges";
|
||||||
|
public static final String confHighlightDurationKey = "highlightDuration";
|
||||||
|
}
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.util;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
|
||||||
|
|
||||||
|
public class FloodUtil {
|
||||||
|
private static final Set<BlockFace> exp1 = new HashSet<>();
|
||||||
|
private static final Set<BlockFace> exp2 = new HashSet<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
exp1.add(BlockFace.UP);
|
||||||
|
exp1.add(BlockFace.DOWN);
|
||||||
|
exp1.add(BlockFace.EAST);
|
||||||
|
exp1.add(BlockFace.WEST);
|
||||||
|
|
||||||
|
exp2.add(BlockFace.UP);
|
||||||
|
exp2.add(BlockFace.DOWN);
|
||||||
|
exp2.add(BlockFace.NORTH);
|
||||||
|
exp2.add(BlockFace.SOUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the all frame blocks of an gate.
|
||||||
|
*
|
||||||
|
* @param blocks All blocks inside the gate.
|
||||||
|
* @return A Set containing all frame block. Will never return 'null'.
|
||||||
|
*/
|
||||||
|
public static Set<Block> getFrame(final Set<Block> blocks) {
|
||||||
|
if (blocks == null || blocks.isEmpty()) {
|
||||||
|
return new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to find gate's direction (north-south or east-west)
|
||||||
|
Set<BlockFace> gateFrameSearchFaces = null;
|
||||||
|
|
||||||
|
for (Block b : blocks) {
|
||||||
|
|
||||||
|
if (blocks.contains(b.getRelative(BlockFace.EAST)) ||
|
||||||
|
blocks.contains(b.getRelative(BlockFace.WEST))) {
|
||||||
|
|
||||||
|
gateFrameSearchFaces = exp1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocks.contains(b.getRelative(BlockFace.NORTH)) ||
|
||||||
|
blocks.contains(b.getRelative(BlockFace.SOUTH))) {
|
||||||
|
|
||||||
|
gateFrameSearchFaces = exp2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gateFrameSearchFaces != null) {
|
||||||
|
return _getFrame(blocks, gateFrameSearchFaces);
|
||||||
|
} else { // no direction found (the gate might only consist of blocks one over another)
|
||||||
|
|
||||||
|
// Try one direction and check if the found blocks are not air.
|
||||||
|
// If air is found (frame broken or wrong direction) return the other direction
|
||||||
|
Set<Block> frameBlocks = _getFrame(blocks, exp1);
|
||||||
|
|
||||||
|
for (Block b : frameBlocks) {
|
||||||
|
|
||||||
|
if (b.getType() == Material.AIR) {
|
||||||
|
return _getFrame(blocks, exp2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frameBlocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Set<Block> _getFrame(final Set<Block> blocks, final Set<BlockFace> searchDirections) {
|
||||||
|
Set<Block> frameBlocks = new HashSet<>();
|
||||||
|
|
||||||
|
for (Block b : blocks) {
|
||||||
|
|
||||||
|
for (BlockFace bf : searchDirections) {
|
||||||
|
Block bb = b.getRelative(bf);
|
||||||
|
|
||||||
|
if (!blocks.contains(bb)) {
|
||||||
|
frameBlocks.add(bb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frameBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the all frame blocks of an gate.
|
||||||
|
*
|
||||||
|
* @param locations All locations inside the gate.
|
||||||
|
* @return A Set containing all frame block. Will never return 'null'.
|
||||||
|
*/
|
||||||
|
public static Set<Block> getFrameWithLocations(final Set<Location> locations) {
|
||||||
|
if (locations == null) {
|
||||||
|
throw new IllegalArgumentException("'locations' must not be 'null'");
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Block> blocks = new HashSet<>();
|
||||||
|
|
||||||
|
for (Location l : locations) {
|
||||||
|
blocks.add(l.getBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
return getFrame(blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// For the same frame and location this set of blocks is deterministic
|
||||||
|
public static Set<Block> getGatePortalBlocks(final Block block) {
|
||||||
|
if (block == null) {
|
||||||
|
throw new IllegalArgumentException("'block' must not be 'null'");
|
||||||
|
}
|
||||||
|
|
||||||
|
int frameBlockSearchLimit = Plugin.getPlugin().getConfig().getInt(ConfigurationUtil.confMaxGateBlocksKey);
|
||||||
|
|
||||||
|
Set<Block> blocks1 = getAirFloodBlocks(block, new HashSet<Block>(), exp1, frameBlockSearchLimit);
|
||||||
|
Set<Block> blocks2 = getAirFloodBlocks(block, new HashSet<Block>(), exp2, frameBlockSearchLimit);
|
||||||
|
|
||||||
|
if (blocks1 == null && blocks2 == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocks1 == null) {
|
||||||
|
return blocks2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocks2 == null) {
|
||||||
|
return blocks1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blocks1.size() > blocks2.size()) {
|
||||||
|
return blocks2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Set<Block> getAirFloodBlocks(final Block startBlock,
|
||||||
|
Set<Block> foundBlocks,
|
||||||
|
final Set<BlockFace> expandFaces,
|
||||||
|
int limit) {
|
||||||
|
if (foundBlocks == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundBlocks.size() > limit) {
|
||||||
|
Plugin.log(Level.ALL, "exceeding gate size limit.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundBlocks.contains(startBlock)) {
|
||||||
|
return foundBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startBlock.getType() == Material.AIR) {
|
||||||
|
foundBlocks.add(startBlock);
|
||||||
|
|
||||||
|
for (BlockFace face : expandFaces) {
|
||||||
|
Block potentialBlock = startBlock.getRelative(face);
|
||||||
|
foundBlocks = getAirFloodBlocks(potentialBlock, foundBlocks, expandFaces, limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundBlocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.util;
|
||||||
|
|
||||||
|
import de.craftinc.gates.Plugin;
|
||||||
|
import de.craftinc.gates.models.Gate;
|
||||||
|
|
||||||
|
import de.craftinc.gates.models.GateMaterial;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static de.craftinc.gates.util.ConfigurationUtil.*;
|
||||||
|
|
||||||
|
public class GateBlockChangeSender {
|
||||||
|
/**
|
||||||
|
* Replaces gate frame blocks with glowstone for a short period of time.
|
||||||
|
* Uses the data stored in 'highlightDuration' inside the config file
|
||||||
|
* for determining when to de-highlight the frames.
|
||||||
|
*
|
||||||
|
* @param player The player for whom the frame should be highlighted.
|
||||||
|
* Must not be null!
|
||||||
|
*
|
||||||
|
* @param gates The gates to highlighting
|
||||||
|
*/
|
||||||
|
public static void temporaryHighlightGatesFrames(final Player player, final Set<Gate> gates) {
|
||||||
|
assert(player != null);
|
||||||
|
assert(gates != null);
|
||||||
|
|
||||||
|
for (Gate g : gates) {
|
||||||
|
Set<Block> frameBlocks = g.getGateFrameBlocks();
|
||||||
|
|
||||||
|
for (Block b : frameBlocks) {
|
||||||
|
player.sendBlockChange(b.getLocation(), Material.GLOWSTONE, (byte) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scheduleDelighting(player, gates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends gate blocks to player at a given location. Will send the updates either immediately or
|
||||||
|
* immediately and after a short delay.
|
||||||
|
*
|
||||||
|
* @param player A player to send block changes to. Must not be null!
|
||||||
|
* @param location The location to look for gates nearby. Must not be null!
|
||||||
|
* @param sendDelayed Set to 'true' if the block changes shall be send a second time after a one
|
||||||
|
* second delay.
|
||||||
|
*/
|
||||||
|
public static void updateGateBlocks(final Player player, final Location location, boolean sendDelayed) {
|
||||||
|
assert(player != null);
|
||||||
|
assert(location != null);
|
||||||
|
|
||||||
|
Set<Gate> gatesNearby = Plugin.getPlugin().getGatesManager().getNearbyGates(location.getChunk());
|
||||||
|
|
||||||
|
if (gatesNearby == null) {
|
||||||
|
return; // no gates nearby
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Gate g : gatesNearby) {
|
||||||
|
if (!g.isOpen()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sendGateBlockChanges(g, true, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendDelayed) {
|
||||||
|
Bukkit.getScheduler().scheduleSyncDelayedTask(Plugin.getPlugin(), new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updateGateBlocks(player, location, false);
|
||||||
|
}
|
||||||
|
}, 20L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateGateBlocks(final Player player, final Location location) {
|
||||||
|
updateGateBlocks(player, location, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void updateGateBlocks(final Gate gate) {
|
||||||
|
updateGateBlocks(gate, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends block changes to players near a given gate.
|
||||||
|
*
|
||||||
|
* @param gate Must not be 'null'!
|
||||||
|
* @param remove Set to true if all visible gate blocks shall be removed.
|
||||||
|
*/
|
||||||
|
public static void updateGateBlocks(final Gate gate, boolean remove) {
|
||||||
|
assert(gate != null);
|
||||||
|
|
||||||
|
Location gateLocation = gate.getLocation();
|
||||||
|
if (gate.getGateBlockLocations().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Player> playersNearby = new ArrayList<>();
|
||||||
|
int searchRadius = Plugin.getPlugin().getConfig().getInt(confPlayerGateBlockUpdateRadiusKey);
|
||||||
|
|
||||||
|
for (Player p : Plugin.getPlugin().getServer().getOnlinePlayers()) {
|
||||||
|
if (p.getWorld() == gateLocation.getWorld() && p.getLocation().distance(gateLocation) < searchRadius) {
|
||||||
|
playersNearby.add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isVisible = gate.isOpen() && !remove;
|
||||||
|
for (Player p : playersNearby) {
|
||||||
|
sendGateBlockChanges(gate, isVisible, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void scheduleDelighting(final Player player, final Set<Gate> gates) {
|
||||||
|
Plugin plugin = Plugin.getPlugin();
|
||||||
|
long highlightDuration = 20 * plugin.getConfig().getLong(confHighlightDurationKey);
|
||||||
|
|
||||||
|
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
dehighlightGatesFrames(player, gates);
|
||||||
|
}
|
||||||
|
}, highlightDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dehighlightGatesFrames(final Player player, final Set<Gate> gates) {
|
||||||
|
for (Gate g : gates) {
|
||||||
|
Set<Block> frameBlocks = g.getGateFrameBlocks();
|
||||||
|
|
||||||
|
for (Block b : frameBlocks) {
|
||||||
|
player.sendBlockChange(b.getLocation(), b.getType(), (byte) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendGateBlockChanges(final Gate gate, boolean isVisible, final Player p) {
|
||||||
|
byte data;
|
||||||
|
Material material;
|
||||||
|
|
||||||
|
if (isVisible) {
|
||||||
|
GateMaterial gm = gate.getMaterial();
|
||||||
|
data = gm.getData(gate.getDirection());
|
||||||
|
material = gm.getMaterial();
|
||||||
|
} else {
|
||||||
|
data = 0b0;
|
||||||
|
material = Material.AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Location l : gate.getGateBlockLocations()) {
|
||||||
|
if (l.getBlock().getType() == Material.AIR) {
|
||||||
|
p.sendBlockChange(l, material, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/* Craft Inc. Gates
|
||||||
|
Copyright (C) 2011-2013 Craft Inc. Gates Team (see AUTHORS.txt)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program (LGPLv3). If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.craftinc.gates.util;
|
||||||
|
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TextUtil {
|
||||||
|
|
||||||
|
public static String titleSize(String str) {
|
||||||
|
String center = ".[ " + ChatColor.YELLOW + str + ChatColor.GOLD + " ].";
|
||||||
|
|
||||||
|
if (center.length() >= 60) {
|
||||||
|
return ChatColor.GOLD + center;
|
||||||
|
} else {
|
||||||
|
String line = ChatColor.GOLD + repeat("_", 60);
|
||||||
|
|
||||||
|
int pivot = line.length() / 2;
|
||||||
|
int eatLeft = center.length() / 2;
|
||||||
|
int eatRight = center.length() - eatLeft;
|
||||||
|
|
||||||
|
return line.substring(0, pivot - eatLeft) + center + line.substring(pivot + eatRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String repeat(String s, int times) {
|
||||||
|
if (times <= 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return s + repeat(s, times - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins all elements of list into a single string, separating the original strings with glue.
|
||||||
|
*/
|
||||||
|
public static String implode(List<String> list, String glue) {
|
||||||
|
if (list.size() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
String ret = list.get(0);
|
||||||
|
|
||||||
|
for (int i = 1; i < list.size(); i++) {
|
||||||
|
ret += glue + list.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
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 = 10.0;
|
|
||||||
|
|
||||||
static {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double getGateSearchRadius() {
|
|
||||||
return gateSearchRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getGateMaxArea() {
|
|
||||||
return (int)gateSearchRadius * 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------- //
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
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<String, Gate> instances = new TreeMap<String, Gate>(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;
|
|
||||||
|
|
||||||
private Integer[][] gateBlocks;
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Integer[][] getGateBlocks()
|
|
||||||
{
|
|
||||||
return gateBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setGateBlocks(Set<Block> gateBlocks)
|
|
||||||
{
|
|
||||||
if (gateBlocks == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.gateBlocks = new Integer[gateBlocks.size()][3];
|
|
||||||
|
|
||||||
int blockcount = 0;
|
|
||||||
for (Block b : gateBlocks)
|
|
||||||
{
|
|
||||||
if (b != null)
|
|
||||||
{
|
|
||||||
this.gateBlocks[blockcount][0] = b.getX();
|
|
||||||
this.gateBlocks[blockcount][1] = b.getY();
|
|
||||||
this.gateBlocks[blockcount][2] = b.getZ();
|
|
||||||
}
|
|
||||||
blockcount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------//
|
|
||||||
// The Open And Close Methods
|
|
||||||
//----------------------------------------------//
|
|
||||||
|
|
||||||
public boolean open()
|
|
||||||
{
|
|
||||||
Set<Block> blocks = FloodUtil.getGateFrameBlocks(from.getBlock());
|
|
||||||
|
|
||||||
if (blocks == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Uncomment lines below to have the old Portal open functionality back.
|
|
||||||
|
|
||||||
// This is not to do an effect
|
|
||||||
// It is to stop portal blocks from destroying themself 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()
|
|
||||||
{
|
|
||||||
if (from != null)
|
|
||||||
{
|
|
||||||
Set<Block> blocks = FloodUtil.getGateFrameBlocks(from.getBlock());
|
|
||||||
|
|
||||||
if (blocks != null)
|
|
||||||
{
|
|
||||||
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 rename(Gate gate, String newId)
|
|
||||||
{
|
|
||||||
delete(gate.id);
|
|
||||||
|
|
||||||
gate.setId(newId);
|
|
||||||
instances.put(gate.id, 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<Map<String, Gate>>(){}.getType();
|
|
||||||
Map<String, Gate> instancesFromFile = Plugin.gson.fromJson(DiscUtil.read(file), type);
|
|
||||||
instances.clear();
|
|
||||||
instances.putAll(instancesFromFile);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fillIds();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Collection<Gate> getAll()
|
|
||||||
{
|
|
||||||
return instances.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void fillIds()
|
|
||||||
{
|
|
||||||
for(Entry<String, Gate> entry : instances.entrySet())
|
|
||||||
entry.getValue().setId(entry.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package org.mcteam.ancientgates;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.World.Environment;
|
|
||||||
import org.bukkit.WorldCreator;
|
|
||||||
import org.mcteam.ancientgates.gson.JsonDeserializationContext;
|
|
||||||
import org.mcteam.ancientgates.gson.JsonDeserializer;
|
|
||||||
import org.mcteam.ancientgates.gson.JsonElement;
|
|
||||||
import org.mcteam.ancientgates.gson.JsonObject;
|
|
||||||
import org.mcteam.ancientgates.gson.JsonParseException;
|
|
||||||
import org.mcteam.ancientgates.gson.JsonSerializationContext;
|
|
||||||
import org.mcteam.ancientgates.gson.JsonSerializer;
|
|
||||||
|
|
||||||
public class MyLocationTypeAdapter implements JsonDeserializer<Location>, JsonSerializer<Location> {
|
|
||||||
private static final String WORLD = "world";
|
|
||||||
private static final String X = "x";
|
|
||||||
private static final String Y = "y";
|
|
||||||
private static final String Z = "z";
|
|
||||||
private static final String YAW = "yaw";
|
|
||||||
private static final String PITCH = "pitch";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Location deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
JsonObject obj = json.getAsJsonObject();
|
|
||||||
|
|
||||||
World world = this.getWorld(obj.get(WORLD).getAsString());
|
|
||||||
double x = obj.get(X).getAsDouble();
|
|
||||||
double y = obj.get(Y).getAsDouble();
|
|
||||||
double z = obj.get(Z).getAsDouble();
|
|
||||||
float yaw = obj.get(YAW).getAsFloat();
|
|
||||||
float pitch = obj.get(PITCH).getAsFloat();
|
|
||||||
|
|
||||||
return new Location(world, x, y, z, yaw, pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(Location src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
JsonObject obj = new JsonObject();
|
|
||||||
|
|
||||||
if (src == null)
|
|
||||||
{
|
|
||||||
Plugin.log("Passed location is null in MyLocationTypeAdapter.");
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
else if (src.getWorld() == null)
|
|
||||||
{
|
|
||||||
Plugin.log("Passed location's world is null in MyLocationTypeAdapter.");
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.addProperty(WORLD, src.getWorld().getName());
|
|
||||||
obj.addProperty(X, src.getX());
|
|
||||||
obj.addProperty(Y, src.getY());
|
|
||||||
obj.addProperty(Z, src.getZ());
|
|
||||||
obj.addProperty(YAW, src.getYaw());
|
|
||||||
obj.addProperty(PITCH, src.getPitch());
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
private World getWorld(String name) {
|
|
||||||
World world = Plugin.instance.getServer().getWorld(name);
|
|
||||||
if (world == null) {
|
|
||||||
world = Plugin.instance.getServer().createWorld(new WorldCreator(name).environment(Environment.NORMAL));
|
|
||||||
}
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
package org.mcteam.ancientgates;
|
|
||||||
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
|
||||||
import org.mcteam.ancientgates.commands.*;
|
|
||||||
import org.mcteam.ancientgates.gson.Gson;
|
|
||||||
import org.mcteam.ancientgates.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import org.mcteam.ancientgates.listeners.PluginBlockListener;
|
|
||||||
import org.mcteam.ancientgates.listeners.PluginPlayerListener;
|
|
||||||
|
|
||||||
|
|
||||||
public class Plugin extends JavaPlugin
|
|
||||||
{
|
|
||||||
public static Plugin instance;
|
|
||||||
|
|
||||||
public PluginPlayerListener playerListener = new PluginPlayerListener();
|
|
||||||
public PluginBlockListener blockListener = new PluginBlockListener();
|
|
||||||
|
|
||||||
private String baseCommand;
|
|
||||||
|
|
||||||
public final static Gson gson = new GsonBuilder()
|
|
||||||
.setPrettyPrinting()
|
|
||||||
.excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.VOLATILE)
|
|
||||||
.registerTypeAdapter(Location.class, new MyLocationTypeAdapter())
|
|
||||||
.create();
|
|
||||||
|
|
||||||
// Commands
|
|
||||||
public List<BaseCommand> commands = new ArrayList<BaseCommand>();
|
|
||||||
|
|
||||||
public Plugin()
|
|
||||||
{
|
|
||||||
instance = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
log("Disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable()
|
|
||||||
{
|
|
||||||
// Add the commands
|
|
||||||
commands.add(new CommandHelp());
|
|
||||||
commands.add(new CommandCreate());
|
|
||||||
commands.add(new CommandCreateSetFrom());
|
|
||||||
commands.add(new CommandDelete());
|
|
||||||
commands.add(new CommandSetFrom());
|
|
||||||
commands.add(new CommandSetTo());
|
|
||||||
commands.add(new CommandOpen());
|
|
||||||
commands.add(new CommandRename());
|
|
||||||
commands.add(new CommandClose());
|
|
||||||
commands.add(new CommandList());
|
|
||||||
commands.add(new CommandInfo());
|
|
||||||
|
|
||||||
// Ensure basefolder exists!
|
|
||||||
this.getDataFolder().mkdirs();
|
|
||||||
|
|
||||||
// Load from disc
|
|
||||||
Conf.load();
|
|
||||||
Gate.load();
|
|
||||||
|
|
||||||
// Register events
|
|
||||||
getServer().getPluginManager().registerEvents(this.playerListener, this);
|
|
||||||
getServer().getPluginManager().registerEvents(this.blockListener, this);
|
|
||||||
|
|
||||||
log("Enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------- //
|
|
||||||
// Test rights
|
|
||||||
// -------------------------------------------- //
|
|
||||||
|
|
||||||
public static boolean hasPermManage(CommandSender sender) {
|
|
||||||
return sender.isOp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------- //
|
|
||||||
// Commands
|
|
||||||
// -------------------------------------------- //
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public String getBaseCommand() {
|
|
||||||
if (this.baseCommand != null) {
|
|
||||||
return this.baseCommand;
|
|
||||||
}
|
|
||||||
Map<String, Map<String, Object>> Commands = (Map<String, Map<String, Object>>) this.getDescription().getCommands();
|
|
||||||
this.baseCommand = Commands.keySet().iterator().next();
|
|
||||||
return this.baseCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
|
|
||||||
List<String> parameters = new ArrayList<String>(Arrays.asList(args));
|
|
||||||
this.handleCommand(sender, parameters);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleCommand(CommandSender sender, List<String> parameters) {
|
|
||||||
if (parameters.size() == 0) {
|
|
||||||
this.commands.get(0).execute(sender, parameters);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String commandName = parameters.get(0).toLowerCase();
|
|
||||||
parameters.remove(0);
|
|
||||||
|
|
||||||
for (BaseCommand fcommand : this.commands) {
|
|
||||||
if (fcommand.getAliases().contains(commandName)) {
|
|
||||||
fcommand.execute(sender, parameters);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.sendMessage(Conf.colorSystem+"Unknown gate-command \""+commandName+"\". Try "+Conf.colorCommand+"/"+getBaseCommand()+" help");
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------- //
|
|
||||||
// Logging
|
|
||||||
// -------------------------------------------- //
|
|
||||||
public static void log(String msg) {
|
|
||||||
log(Level.INFO, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void log(Level level, String msg) {
|
|
||||||
Logger.getLogger("Minecraft").log(level, "["+instance.getDescription().getFullName()+"] "+msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
import org.mcteam.ancientgates.Plugin;
|
|
||||||
import org.mcteam.ancientgates.Conf;
|
|
||||||
import org.mcteam.ancientgates.util.TextUtil;
|
|
||||||
|
|
||||||
public class BaseCommand
|
|
||||||
{
|
|
||||||
public List<String> aliases;
|
|
||||||
public List<String> requiredParameters;
|
|
||||||
public List<String> optionalParameters;
|
|
||||||
|
|
||||||
public String helpDescription;
|
|
||||||
|
|
||||||
public CommandSender sender;
|
|
||||||
public boolean senderMustBePlayer;
|
|
||||||
public boolean hasGateParam;
|
|
||||||
public Player player;
|
|
||||||
public Gate gate;
|
|
||||||
|
|
||||||
public List<String> parameters;
|
|
||||||
|
|
||||||
|
|
||||||
public BaseCommand()
|
|
||||||
{
|
|
||||||
aliases = new ArrayList<String>();
|
|
||||||
requiredParameters = new ArrayList<String>();
|
|
||||||
optionalParameters = new ArrayList<String>();
|
|
||||||
|
|
||||||
senderMustBePlayer = true;
|
|
||||||
hasGateParam = true;
|
|
||||||
|
|
||||||
helpDescription = "no description";
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getAliases() {
|
|
||||||
return aliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void execute(CommandSender sender, List<String> parameters) {
|
|
||||||
this.sender = sender;
|
|
||||||
this.parameters = parameters;
|
|
||||||
|
|
||||||
if ( ! validateCall()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.senderMustBePlayer) {
|
|
||||||
this.player = (Player)sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
perform();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendMessage(String message) {
|
|
||||||
sender.sendMessage(Conf.colorSystem+message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendMessage(List<String> messages) {
|
|
||||||
for(String message : messages) {
|
|
||||||
this.sendMessage(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean validateCall()
|
|
||||||
{
|
|
||||||
// validate player
|
|
||||||
if ( this.senderMustBePlayer && ! (sender instanceof Player))
|
|
||||||
{
|
|
||||||
sendMessage("This command can only be used by ingame players.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate permission
|
|
||||||
if( ! hasPermission(sender))
|
|
||||||
{
|
|
||||||
sendMessage("You lack the permissions to "+this.helpDescription.toLowerCase()+".");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// valide parameter count
|
|
||||||
if (parameters.size() < requiredParameters.size())
|
|
||||||
{
|
|
||||||
sendMessage("Usage: "+this.getUseageTemplate(true));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate gate parameter
|
|
||||||
if (this.hasGateParam)
|
|
||||||
{
|
|
||||||
String id = parameters.get(0);
|
|
||||||
|
|
||||||
if ( ! Gate.exists(id))
|
|
||||||
{
|
|
||||||
sendMessage("There exists no gate with id "+id);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
gate = Gate.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasPermission(CommandSender sender) {
|
|
||||||
return Plugin.hasPermManage(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------- //
|
|
||||||
// Help and usage description
|
|
||||||
// -------------------------------------------- //
|
|
||||||
public String getUseageTemplate(boolean withColor, boolean withDescription) {
|
|
||||||
String ret = "";
|
|
||||||
|
|
||||||
if (withColor) {
|
|
||||||
ret += Conf.colorCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret += "/" + Plugin.instance.getBaseCommand()+ " " +TextUtil.implode(this.getAliases(), ",")+" ";
|
|
||||||
|
|
||||||
List<String> parts = new ArrayList<String>();
|
|
||||||
|
|
||||||
for (String requiredParameter : this.requiredParameters) {
|
|
||||||
parts.add("["+requiredParameter+"]");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String optionalParameter : this.optionalParameters) {
|
|
||||||
parts.add("*["+optionalParameter+"]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (withColor) {
|
|
||||||
ret += Conf.colorParameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret += TextUtil.implode(parts, " ");
|
|
||||||
|
|
||||||
if (withDescription) {
|
|
||||||
ret += " "+Conf.colorSystem + this.helpDescription;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUseageTemplate(boolean withColor) {
|
|
||||||
return getUseageTemplate(withColor, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUseageTemplate() {
|
|
||||||
return getUseageTemplate(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
public class CommandClose extends BaseCommand {
|
|
||||||
|
|
||||||
public CommandClose() {
|
|
||||||
aliases.add("close");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
helpDescription = "Close that gate";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform() {
|
|
||||||
gate.close();
|
|
||||||
sendMessage("The gate was closed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
|
|
||||||
public class CommandCreate extends BaseCommand {
|
|
||||||
public CommandCreate() {
|
|
||||||
aliases.add("create");
|
|
||||||
aliases.add("new");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
senderMustBePlayer = false;
|
|
||||||
hasGateParam = false;
|
|
||||||
|
|
||||||
helpDescription = "Create a gate";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform() {
|
|
||||||
String id = parameters.get(0);
|
|
||||||
if (Gate.exists(id)) {
|
|
||||||
sendMessage("There gate \"" + id + "\" already exists.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gate.create(id);
|
|
||||||
sendMessage("Gate with id \"" + id + "\" was created. Now you should:");
|
|
||||||
sendMessage(new CommandSetFrom().getUseageTemplate(true, true));
|
|
||||||
|
|
||||||
Gate.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.BlockFace;
|
|
||||||
import org.mcteam.ancientgates.Conf;
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
import org.mcteam.ancientgates.util.FloodUtil;
|
|
||||||
|
|
||||||
public class CommandCreateSetFrom extends BaseCommand
|
|
||||||
{
|
|
||||||
public CommandCreateSetFrom()
|
|
||||||
{
|
|
||||||
aliases.add("createsetfrom");
|
|
||||||
aliases.add("newsetfrom");
|
|
||||||
aliases.add("csf");
|
|
||||||
aliases.add("nsf");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
hasGateParam = false;
|
|
||||||
|
|
||||||
helpDescription = "Create a gate and set \"from\" to your location.";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform()
|
|
||||||
{
|
|
||||||
String id = parameters.get(0);
|
|
||||||
|
|
||||||
if (Gate.exists(id)) {
|
|
||||||
sendMessage("There gate \"" + id + "\" already exists.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gate.create(id);
|
|
||||||
Gate.save();
|
|
||||||
sendMessage("Gate with id \"" + id + "\" was created.");
|
|
||||||
|
|
||||||
gate = Gate.get(id);
|
|
||||||
|
|
||||||
// The player might stand in a halfblock or a sign or whatever
|
|
||||||
// Therefore we load som extra locations and blocks
|
|
||||||
Block playerBlock = player.getLocation().getBlock();
|
|
||||||
Block upBlock = playerBlock.getRelative(BlockFace.UP);
|
|
||||||
Location playerUpLocation = new Location(player.getLocation().getWorld(),
|
|
||||||
player.getLocation().getX(),
|
|
||||||
player.getLocation().getY() + 1,
|
|
||||||
player.getLocation().getZ(),
|
|
||||||
player.getLocation().getYaw(),
|
|
||||||
player.getLocation().getPitch());
|
|
||||||
|
|
||||||
Set<Block> gateBlocks = FloodUtil.getGateFrameBlocks(player.getLocation().getBlock());
|
|
||||||
|
|
||||||
if (gateBlocks == null)
|
|
||||||
{
|
|
||||||
sendMessage("Could not set from! Your portal is too large.\nMax size is: " + Conf.getGateMaxArea() + " Blocks.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerBlock.getType() == Material.AIR)
|
|
||||||
{
|
|
||||||
gate.setFrom(player.getLocation());
|
|
||||||
gate.setGateBlocks(gateBlocks);
|
|
||||||
}
|
|
||||||
else if (upBlock.getType() == Material.AIR)
|
|
||||||
{
|
|
||||||
gate.setFrom(playerUpLocation);
|
|
||||||
gate.setGateBlocks(gateBlocks);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sendMessage("Could not set from! There is not enough room for a gate to open here");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage("From location for gate \""+gate.getId()+"\" is now where you stand.");
|
|
||||||
sendMessage("Your gate includes " + gateBlocks.size() + " Blocks.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
|
|
||||||
public class CommandDelete extends BaseCommand {
|
|
||||||
public CommandDelete() {
|
|
||||||
aliases.add("delete");
|
|
||||||
aliases.add("del");
|
|
||||||
aliases.add("remove");
|
|
||||||
aliases.add("rm");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
senderMustBePlayer = false;
|
|
||||||
helpDescription = "Delete a gate";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform() {
|
|
||||||
gate.close();
|
|
||||||
sendMessage("Gate with id \"" + gate.getId() + "\" was deleted.");
|
|
||||||
Gate.delete(gate.getId());
|
|
||||||
Gate.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.mcteam.ancientgates.util.TextUtil;
|
|
||||||
|
|
||||||
public class CommandHelp extends BaseCommand {
|
|
||||||
|
|
||||||
public CommandHelp() {
|
|
||||||
aliases.add("help");
|
|
||||||
aliases.add("h");
|
|
||||||
aliases.add("?");
|
|
||||||
|
|
||||||
optionalParameters.add("page");
|
|
||||||
hasGateParam = false;
|
|
||||||
|
|
||||||
helpDescription = "Display a help page";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(CommandSender sender) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void perform()
|
|
||||||
{
|
|
||||||
int page = 1;
|
|
||||||
|
|
||||||
if (parameters.size() > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
page = Integer.parseInt(parameters.get(0));
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
// wasn't an integer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(TextUtil.titleize("AncientGates Help ("+page+"/"+helpPages.size()+")"));
|
|
||||||
|
|
||||||
page -= 1;
|
|
||||||
if (page < 0 || page >= helpPages.size())
|
|
||||||
{
|
|
||||||
sendMessage("This page does not exist");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(helpPages.get(page));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------//
|
|
||||||
// Build the help pages
|
|
||||||
//----------------------------------------------//
|
|
||||||
|
|
||||||
public static ArrayList<ArrayList<String>> helpPages;
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
helpPages = new ArrayList<ArrayList<String>>();
|
|
||||||
ArrayList<String> pageLines;
|
|
||||||
|
|
||||||
pageLines = new ArrayList<String>();
|
|
||||||
pageLines.add( new CommandHelp().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandCreate().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandCreateSetFrom().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandDelete().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandSetFrom().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandSetTo().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandOpen().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandRename().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandClose().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandList().getUseageTemplate(true, true) );
|
|
||||||
pageLines.add( new CommandInfo().getUseageTemplate(true, true) );
|
|
||||||
helpPages.add(pageLines);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
|
|
||||||
|
|
||||||
public class CommandInfo extends BaseCommand
|
|
||||||
{
|
|
||||||
public CommandInfo()
|
|
||||||
{
|
|
||||||
aliases.add("info");
|
|
||||||
aliases.add("details");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
helpDescription = "Prints information about a gate";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void perform()
|
|
||||||
{
|
|
||||||
sendMessage(ChatColor.LIGHT_PURPLE + "Information about " + ChatColor.WHITE + gate.getId() + ChatColor.LIGHT_PURPLE + ":");
|
|
||||||
|
|
||||||
if (gate.getFrom() != null)
|
|
||||||
sendMessage(ChatColor.GREEN + "'from' location: " + ChatColor.YELLOW + "( " + gate.getFrom().getBlockX() + " | " + gate.getFrom().getBlockY() + " | " + gate.getFrom().getBlockZ() + " )");
|
|
||||||
else
|
|
||||||
sendMessage(ChatColor.GREEN + "this gate has no 'from' location");
|
|
||||||
|
|
||||||
if (gate.getTo() != null)
|
|
||||||
sendMessage(ChatColor.GREEN + "'to' location: " + ChatColor.YELLOW + "( " + gate.getTo().getBlockX() + " | " + gate.getTo().getBlockY() + " | " + gate.getTo().getBlockZ() + " )");
|
|
||||||
else
|
|
||||||
sendMessage(ChatColor.GREEN + "this gate has no 'to' location");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.mcteam.ancientgates.Conf;
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
import org.mcteam.ancientgates.util.TextUtil;
|
|
||||||
|
|
||||||
public class CommandList extends BaseCommand
|
|
||||||
{
|
|
||||||
public CommandList()
|
|
||||||
{
|
|
||||||
aliases.add("list");
|
|
||||||
aliases.add("ls");
|
|
||||||
|
|
||||||
optionalParameters.add("page");
|
|
||||||
hasGateParam = false;
|
|
||||||
|
|
||||||
helpDescription = "Display a list of the gates";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected String intToTitleString(int i)
|
|
||||||
{
|
|
||||||
if ( i < 26 )
|
|
||||||
return Conf.colorMember + "" + (char)(i+65) + ":";
|
|
||||||
else if ( i == 26 )
|
|
||||||
return Conf.colorMember + "0 - 9:";
|
|
||||||
else
|
|
||||||
return Conf.colorMember + "!@#$:";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// pages start at 1
|
|
||||||
// will return null if requested page not availible
|
|
||||||
protected List<String> message(int page)
|
|
||||||
{
|
|
||||||
Collection<Gate> gates = Gate.getAll();
|
|
||||||
|
|
||||||
if (gates.size() == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
/* sort all gates by there first character
|
|
||||||
* put gates in corresponding Lists
|
|
||||||
* list 0-25: a,b,c, ... ,z
|
|
||||||
* list 26: 0-9
|
|
||||||
* list 27: other
|
|
||||||
*/
|
|
||||||
List<List<String>> ids = new ArrayList<List<String>>();
|
|
||||||
|
|
||||||
for (int i=0; i<28; i++)
|
|
||||||
ids.add(new ArrayList<String>());
|
|
||||||
|
|
||||||
for (Gate gate : gates)
|
|
||||||
{
|
|
||||||
String id = gate.getId();
|
|
||||||
int first = id.charAt(0);
|
|
||||||
|
|
||||||
if (first > 96 && first < 123) // convert lower case chars
|
|
||||||
first -= 97;
|
|
||||||
else if (first > 64 && first < 91) // convert upper case chars
|
|
||||||
first -= 65;
|
|
||||||
else if (first > 47 && first < 58) // convert numbers
|
|
||||||
first = 26;
|
|
||||||
else // everything else
|
|
||||||
first = 27;
|
|
||||||
|
|
||||||
ids.get(first).add(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* calculating which gates will be displayed on which page.
|
|
||||||
* this is a little bit fuzzy. but hopefully it will look
|
|
||||||
* great. (tell me if there is a better way!)
|
|
||||||
*/
|
|
||||||
|
|
||||||
// list<string>: a list from ids
|
|
||||||
// Integer: the number of lines neccessary for displaying the corresponding list
|
|
||||||
HashMap<List<String>, Integer> lines = new HashMap<List<String>, Integer>(27);
|
|
||||||
|
|
||||||
for (List<String> currentIds : ids)
|
|
||||||
{
|
|
||||||
if (currentIds.size() == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int characters = TextUtil.implode(currentIds, ", ").length();
|
|
||||||
lines.put(currentIds, characters / 52 + 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int currentPage = 1;
|
|
||||||
int currentStartingCharList = 0;
|
|
||||||
boolean finishedCurrentIds = true;
|
|
||||||
|
|
||||||
List<String> pageMessages = new ArrayList<String>();
|
|
||||||
|
|
||||||
while (currentStartingCharList < ids.size())
|
|
||||||
{
|
|
||||||
int linesLeftOnCurrentPage = 9;
|
|
||||||
|
|
||||||
while (linesLeftOnCurrentPage > 1 && currentStartingCharList < ids.size())
|
|
||||||
{
|
|
||||||
List<String> currentIds = ids.get(currentStartingCharList);
|
|
||||||
|
|
||||||
if (currentIds.size() > 0)
|
|
||||||
{
|
|
||||||
// add header line
|
|
||||||
if (currentPage == page)
|
|
||||||
pageMessages.add(intToTitleString(currentStartingCharList));
|
|
||||||
|
|
||||||
//sort
|
|
||||||
Collections.sort(currentIds);
|
|
||||||
|
|
||||||
// add ids
|
|
||||||
if (lines.get(currentIds) <= linesLeftOnCurrentPage) // all ids fit on current page
|
|
||||||
{
|
|
||||||
linesLeftOnCurrentPage -= lines.get(currentIds);
|
|
||||||
|
|
||||||
|
|
||||||
if (currentPage == page)
|
|
||||||
{
|
|
||||||
pageMessages.add(TextUtil.implode(currentIds, ", "));
|
|
||||||
if (finishedCurrentIds == false)
|
|
||||||
pageMessages.set(pageMessages.size() -2, pageMessages.get(pageMessages.size() -2) + " (more on previous page)");
|
|
||||||
}
|
|
||||||
|
|
||||||
finishedCurrentIds = true;
|
|
||||||
}
|
|
||||||
else // NOT all ids fit on current page
|
|
||||||
{
|
|
||||||
int charsAvailible = (linesLeftOnCurrentPage - 1) * 52;
|
|
||||||
int idsPos = 0;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
charsAvailible -= currentIds.get(idsPos).length() + 2;
|
|
||||||
|
|
||||||
if (charsAvailible <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
idsPos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> idsToPutOnCurrentPage = currentIds.subList(0, idsPos);
|
|
||||||
currentIds.remove(idsToPutOnCurrentPage);
|
|
||||||
|
|
||||||
String stringToPutOnCurrentPage = TextUtil.implode(idsToPutOnCurrentPage, ", ");
|
|
||||||
|
|
||||||
if (currentPage == page)
|
|
||||||
{
|
|
||||||
pageMessages.add(stringToPutOnCurrentPage);
|
|
||||||
pageMessages.set(pageMessages.size() -2, pageMessages.get(pageMessages.size() -2) + " (more on next page)");
|
|
||||||
}
|
|
||||||
|
|
||||||
lines.put(currentIds, TextUtil.implode(currentIds, ", ").length() / 52 + 2);
|
|
||||||
linesLeftOnCurrentPage -= stringToPutOnCurrentPage.length() / 52 + 2;
|
|
||||||
|
|
||||||
finishedCurrentIds = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finishedCurrentIds)
|
|
||||||
currentStartingCharList++;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPage++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pageMessages.isEmpty())
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArrayList<String> retVal = new ArrayList<String>();
|
|
||||||
retVal.add(ChatColor.LIGHT_PURPLE + "This is page " + ChatColor.WHITE + page + ChatColor.LIGHT_PURPLE + "/" + ChatColor.WHITE + --currentPage + ChatColor.LIGHT_PURPLE + ". There are " + gates.size() + " gates on this server: ");
|
|
||||||
retVal.addAll(pageMessages);
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void perform()
|
|
||||||
{
|
|
||||||
Collection<Gate> gates = Gate.getAll();
|
|
||||||
|
|
||||||
if (gates.size() == 0)
|
|
||||||
sendMessage("There are no gates yet.");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int page = 1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
page = new Integer(parameters.get(0));
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> messages = message(page);
|
|
||||||
|
|
||||||
if (messages == null)
|
|
||||||
sendMessage("The requested page is not availible");
|
|
||||||
else
|
|
||||||
sendMessage(messages);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
|
|
||||||
public class CommandOpen extends BaseCommand {
|
|
||||||
|
|
||||||
public CommandOpen() {
|
|
||||||
aliases.add("open");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
helpDescription = "Open that gate";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform() {
|
|
||||||
if (gate.getFrom() == null) {
|
|
||||||
sendMessage("You must set the from location first. To fix that:");
|
|
||||||
sendMessage(new CommandSetFrom().getUseageTemplate(true, true));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gate.getTo() == null) {
|
|
||||||
sendMessage("Sure, but note that this gate does not point anywhere :P");
|
|
||||||
sendMessage("To fix that: " + new CommandSetTo().getUseageTemplate(true, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gate.getFrom().getBlock().getType() != Material.AIR) {
|
|
||||||
sendMessage("The gate could not open. The from location is not air.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gate.open()) {
|
|
||||||
sendMessage("The gate was opened.");
|
|
||||||
} else {
|
|
||||||
sendMessage("Failed to open the gate. Have you built a frame?");
|
|
||||||
sendMessage("More info here: " + new CommandHelp().getUseageTemplate(true, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class CommandRename extends BaseCommand
|
|
||||||
{
|
|
||||||
public CommandRename()
|
|
||||||
{
|
|
||||||
aliases.add("rename");
|
|
||||||
aliases.add("changename");
|
|
||||||
aliases.add("cn");
|
|
||||||
|
|
||||||
hasGateParam = true;
|
|
||||||
senderMustBePlayer = false;
|
|
||||||
|
|
||||||
requiredParameters.add("current name");
|
|
||||||
requiredParameters.add("new name");
|
|
||||||
|
|
||||||
helpDescription = "Change the name of a gate";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void perform()
|
|
||||||
{
|
|
||||||
String newId = parameters.get(1);
|
|
||||||
String oldId = gate.getId();
|
|
||||||
|
|
||||||
if (Gate.exists(newId))
|
|
||||||
{
|
|
||||||
sendMessage("Cannot rename " + oldId + ". There is already a gate named " + newId + ".");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gate.rename(gate, newId);
|
|
||||||
|
|
||||||
sendMessage("Gate " + oldId + " is now known as " + newId + ".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.BlockFace;
|
|
||||||
import org.mcteam.ancientgates.Conf;
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
import org.mcteam.ancientgates.util.FloodUtil;
|
|
||||||
|
|
||||||
public class CommandSetFrom extends BaseCommand {
|
|
||||||
|
|
||||||
public CommandSetFrom() {
|
|
||||||
aliases.add("setfrom");
|
|
||||||
aliases.add("sf");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
helpDescription = "Set \"from\" to your location.";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform() {
|
|
||||||
// The player might stand in a halfblock or a sign or whatever
|
|
||||||
// Therefore we load som extra locations and blocks
|
|
||||||
Block playerBlock = player.getLocation().getBlock();
|
|
||||||
Block upBlock = playerBlock.getRelative(BlockFace.UP);
|
|
||||||
Location playerUpLocation = new Location(player.getLocation().getWorld(),
|
|
||||||
player.getLocation().getX(),
|
|
||||||
player.getLocation().getY() + 1,
|
|
||||||
player.getLocation().getZ(),
|
|
||||||
player.getLocation().getYaw(),
|
|
||||||
player.getLocation().getPitch());
|
|
||||||
|
|
||||||
Set<Block> gateBlocks = FloodUtil.getGateFrameBlocks(player.getLocation().getBlock());
|
|
||||||
if (gateBlocks == null) {
|
|
||||||
sendMessage("There is no portal here, or your portal is too large.\nMax size is: " + Conf.getGateMaxArea() + " Blocks.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerBlock.getType() == Material.AIR) {
|
|
||||||
gate.setFrom(player.getLocation());
|
|
||||||
gate.setGateBlocks(gateBlocks);
|
|
||||||
} else if (upBlock.getType() == Material.AIR) {
|
|
||||||
gate.setFrom(playerUpLocation);
|
|
||||||
gate.setGateBlocks(gateBlocks);
|
|
||||||
} else {
|
|
||||||
sendMessage("There is not enough room for a gate to open here");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sendMessage("From location for gate \""+gate.getId()+"\" is now where you stand.");
|
|
||||||
sendMessage("Your gate includes " + gateBlocks.size() + " Blocks.");
|
|
||||||
|
|
||||||
Gate.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.commands;
|
|
||||||
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
|
|
||||||
public class CommandSetTo extends BaseCommand {
|
|
||||||
|
|
||||||
public CommandSetTo() {
|
|
||||||
aliases.add("setto");
|
|
||||||
|
|
||||||
requiredParameters.add("id");
|
|
||||||
|
|
||||||
helpDescription = "Set \"to\" to your location.";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform() {
|
|
||||||
gate.setTo(player.getLocation());
|
|
||||||
sendMessage("To location for gate \""+gate.getId()+"\" is now where you stand.");
|
|
||||||
|
|
||||||
Gate.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strategy for excluding anonymous and local classes.
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class AnonymousAndLocalClassExclusionStrategy implements ExclusionStrategy {
|
|
||||||
|
|
||||||
public boolean shouldSkipField(FieldAttributes f) {
|
|
||||||
return isAnonymousOrLocal(f.getDeclaredClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldSkipClass(Class<?> clazz) {
|
|
||||||
return isAnonymousOrLocal(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAnonymousOrLocal(Class<?> clazz) {
|
|
||||||
return !Enum.class.isAssignableFrom(clazz)
|
|
||||||
&& (clazz.isAnonymousClass() || clazz.isLocalClass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines generic cache interface.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
interface Cache<K, V> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the new value object into the cache for the given key. If the key already
|
|
||||||
* exists, then this method will override the value for the key.
|
|
||||||
*
|
|
||||||
* @param key the key identifier for the {@code value} object
|
|
||||||
* @param value the value object to store in the cache
|
|
||||||
*/
|
|
||||||
void addElement(K key, V value);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the cached value for the given {@code key}.
|
|
||||||
*
|
|
||||||
* @param key the key identifying the value
|
|
||||||
* @return the cached value for the given {@code key}
|
|
||||||
*/
|
|
||||||
V getElement(K key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the value from the cache for the given key.
|
|
||||||
*
|
|
||||||
* @param key the key identifying the value to remove
|
|
||||||
* @return the value for the given {@code key}
|
|
||||||
*/
|
|
||||||
V removeElement(K key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes everything from this cache.
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the number of objects in this cache
|
|
||||||
*/
|
|
||||||
int size();
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the field name that uses camel-case define word separation into separate words that
|
|
||||||
* are separated by the provided {@code separatorString}.
|
|
||||||
*
|
|
||||||
* <p>The following is an example:</p>
|
|
||||||
* <pre>
|
|
||||||
* class IntWrapper {
|
|
||||||
* public int integerField = 0;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* CamelCaseSeparatorNamingPolicy policy = new CamelCaseSeparatorNamingPolicy("_");
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
|
||||||
*
|
|
||||||
* assert("integer_Field".equals(translatedFieldName));
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class CamelCaseSeparatorNamingPolicy extends RecursiveFieldNamingPolicy {
|
|
||||||
private final String separatorString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new CamelCaseSeparatorNamingPolicy object that will add the
|
|
||||||
* {@code separatorString} between each of the words separated by camel case.
|
|
||||||
*
|
|
||||||
* @param separatorString the string value to place between words
|
|
||||||
* @throws IllegalArgumentException thrown if the {@code separatorString} parameter
|
|
||||||
* is null or empty.
|
|
||||||
*/
|
|
||||||
public CamelCaseSeparatorNamingPolicy(String separatorString) {
|
|
||||||
Preconditions.checkNotNull(separatorString);
|
|
||||||
Preconditions.checkArgument(!"".equals(separatorString));
|
|
||||||
this.separatorString = separatorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String translateName(String target, Type fieldType,
|
|
||||||
Collection<Annotation> annnotations) {
|
|
||||||
StringBuilder translation = new StringBuilder();
|
|
||||||
for (int i = 0; i < target.length(); i++) {
|
|
||||||
char character = target.charAt(i);
|
|
||||||
if (Character.isUpperCase(character) && translation.length() != 0) {
|
|
||||||
translation.append(separatorString);
|
|
||||||
}
|
|
||||||
translation.append(character);
|
|
||||||
}
|
|
||||||
|
|
||||||
return translation.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception class to indicate a circular reference error.
|
|
||||||
* This class is not part of the public API and hence is not public.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class CircularReferenceException extends RuntimeException {
|
|
||||||
private static final long serialVersionUID = 7444343294106513081L;
|
|
||||||
private final Object offendingNode;
|
|
||||||
|
|
||||||
CircularReferenceException(Object offendingNode) {
|
|
||||||
super("circular reference error");
|
|
||||||
this.offendingNode = offendingNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IllegalStateException createDetailedException(FieldAttributes offendingField) {
|
|
||||||
StringBuilder msg = new StringBuilder(getMessage());
|
|
||||||
if (offendingField != null) {
|
|
||||||
msg.append("\n ").append("Offending field: ").append(offendingField.getName() + "\n");
|
|
||||||
}
|
|
||||||
if (offendingNode != null) {
|
|
||||||
msg.append("\n ").append("Offending object: ").append(offendingNode);
|
|
||||||
}
|
|
||||||
return new IllegalStateException(msg.toString(), this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs numerous field naming translations wrapped up as one object.
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
abstract class CompositionFieldNamingPolicy extends RecursiveFieldNamingPolicy {
|
|
||||||
|
|
||||||
private final RecursiveFieldNamingPolicy[] fieldPolicies;
|
|
||||||
|
|
||||||
public CompositionFieldNamingPolicy(RecursiveFieldNamingPolicy... fieldNamingPolicies) {
|
|
||||||
if (fieldNamingPolicies == null) {
|
|
||||||
throw new NullPointerException("naming policies can not be null.");
|
|
||||||
}
|
|
||||||
this.fieldPolicies = fieldNamingPolicies;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
|
||||||
for (RecursiveFieldNamingPolicy policy : fieldPolicies) {
|
|
||||||
target = policy.translateName(target, fieldType, annotations);
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,893 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.sql.Time;
|
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.SortedSet;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of all the default type adapters ({@link JsonSerializer}s, {@link JsonDeserializer}s,
|
|
||||||
* and {@link InstanceCreator}s.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class DefaultTypeAdapters {
|
|
||||||
|
|
||||||
private static final DefaultDateTypeAdapter DATE_TYPE_ADAPTER = new DefaultDateTypeAdapter();
|
|
||||||
private static final DefaultJavaSqlDateTypeAdapter JAVA_SQL_DATE_TYPE_ADAPTER =
|
|
||||||
new DefaultJavaSqlDateTypeAdapter();
|
|
||||||
private static final DefaultTimeTypeAdapter TIME_TYPE_ADAPTER =
|
|
||||||
new DefaultTimeTypeAdapter();
|
|
||||||
private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER =
|
|
||||||
new DefaultTimestampDeserializer();
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter();
|
|
||||||
private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter();
|
|
||||||
private static final UriTypeAdapter URI_TYPE_ADAPTER = new UriTypeAdapter();
|
|
||||||
private static final UuidTypeAdapter UUUID_TYPE_ADAPTER = new UuidTypeAdapter();
|
|
||||||
private static final LocaleTypeAdapter LOCALE_TYPE_ADAPTER = new LocaleTypeAdapter();
|
|
||||||
private static final CollectionTypeAdapter COLLECTION_TYPE_ADAPTER = new CollectionTypeAdapter();
|
|
||||||
private static final MapTypeAdapter MAP_TYPE_ADAPTER = new MapTypeAdapter();
|
|
||||||
private static final BigDecimalTypeAdapter BIG_DECIMAL_TYPE_ADAPTER = new BigDecimalTypeAdapter();
|
|
||||||
private static final BigIntegerTypeAdapter BIG_INTEGER_TYPE_ADAPTER = new BigIntegerTypeAdapter();
|
|
||||||
|
|
||||||
private static final BooleanTypeAdapter BOOLEAN_TYPE_ADAPTER = new BooleanTypeAdapter();
|
|
||||||
private static final ByteTypeAdapter BYTE_TYPE_ADAPTER = new ByteTypeAdapter();
|
|
||||||
private static final CharacterTypeAdapter CHARACTER_TYPE_ADAPTER = new CharacterTypeAdapter();
|
|
||||||
private static final DoubleDeserializer DOUBLE_TYPE_ADAPTER = new DoubleDeserializer();
|
|
||||||
private static final FloatDeserializer FLOAT_TYPE_ADAPTER = new FloatDeserializer();
|
|
||||||
private static final IntegerTypeAdapter INTEGER_TYPE_ADAPTER = new IntegerTypeAdapter();
|
|
||||||
private static final LongDeserializer LONG_DESERIALIZER = new LongDeserializer();
|
|
||||||
private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter();
|
|
||||||
private static final ShortTypeAdapter SHORT_TYPE_ADAPTER = new ShortTypeAdapter();
|
|
||||||
private static final StringTypeAdapter STRING_TYPE_ADAPTER = new StringTypeAdapter();
|
|
||||||
|
|
||||||
private static final PropertiesCreator PROPERTIES_CREATOR = new PropertiesCreator();
|
|
||||||
private static final TreeSetCreator TREE_SET_CREATOR = new TreeSetCreator();
|
|
||||||
private static final HashSetCreator HASH_SET_CREATOR = new HashSetCreator();
|
|
||||||
private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER =
|
|
||||||
new GregorianCalendarTypeAdapter();
|
|
||||||
|
|
||||||
// The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS
|
|
||||||
// must be defined after the constants for the type adapters. Otherwise, the type adapter
|
|
||||||
// constants will appear as nulls.
|
|
||||||
private static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS =
|
|
||||||
createDefaultSerializers();
|
|
||||||
private static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS =
|
|
||||||
createDefaultDeserializers();
|
|
||||||
private static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS =
|
|
||||||
createDefaultInstanceCreators();
|
|
||||||
|
|
||||||
private static ParameterizedTypeHandlerMap<JsonSerializer<?>> createDefaultSerializers() {
|
|
||||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> map =
|
|
||||||
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
|
||||||
|
|
||||||
map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER);
|
|
||||||
map.register(URL.class, URL_TYPE_ADAPTER);
|
|
||||||
map.register(URI.class, URI_TYPE_ADAPTER);
|
|
||||||
map.register(UUID.class, UUUID_TYPE_ADAPTER);
|
|
||||||
map.register(Locale.class, LOCALE_TYPE_ADAPTER);
|
|
||||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
|
||||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
|
||||||
map.register(Date.class, DATE_TYPE_ADAPTER);
|
|
||||||
map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER);
|
|
||||||
map.register(Timestamp.class, DATE_TYPE_ADAPTER);
|
|
||||||
map.register(Time.class, TIME_TYPE_ADAPTER);
|
|
||||||
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
|
||||||
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
|
||||||
map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER);
|
|
||||||
map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER);
|
|
||||||
|
|
||||||
// Add primitive serializers
|
|
||||||
map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER);
|
|
||||||
map.register(boolean.class, BOOLEAN_TYPE_ADAPTER);
|
|
||||||
map.register(Byte.class, BYTE_TYPE_ADAPTER);
|
|
||||||
map.register(byte.class, BYTE_TYPE_ADAPTER);
|
|
||||||
map.register(Character.class, CHARACTER_TYPE_ADAPTER);
|
|
||||||
map.register(char.class, CHARACTER_TYPE_ADAPTER);
|
|
||||||
map.register(Integer.class, INTEGER_TYPE_ADAPTER);
|
|
||||||
map.register(int.class, INTEGER_TYPE_ADAPTER);
|
|
||||||
map.register(Number.class, NUMBER_TYPE_ADAPTER);
|
|
||||||
map.register(Short.class, SHORT_TYPE_ADAPTER);
|
|
||||||
map.register(short.class, SHORT_TYPE_ADAPTER);
|
|
||||||
map.register(String.class, STRING_TYPE_ADAPTER);
|
|
||||||
|
|
||||||
map.makeUnmodifiable();
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultDeserializers() {
|
|
||||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map =
|
|
||||||
new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
|
||||||
map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER));
|
|
||||||
map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER));
|
|
||||||
map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER));
|
|
||||||
map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER));
|
|
||||||
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
|
|
||||||
map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER));
|
|
||||||
map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
|
|
||||||
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
|
|
||||||
map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER));
|
|
||||||
map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER));
|
|
||||||
map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER));
|
|
||||||
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
|
||||||
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
|
||||||
map.register(BigDecimal.class, wrapDeserializer(BIG_DECIMAL_TYPE_ADAPTER));
|
|
||||||
map.register(BigInteger.class, wrapDeserializer(BIG_INTEGER_TYPE_ADAPTER));
|
|
||||||
|
|
||||||
// Add primitive deserializers
|
|
||||||
map.register(Boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
|
|
||||||
map.register(boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
|
|
||||||
map.register(Byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
|
|
||||||
map.register(byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
|
|
||||||
map.register(Character.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
|
|
||||||
map.register(char.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
|
|
||||||
map.register(Double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER));
|
|
||||||
map.register(double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER));
|
|
||||||
map.register(Float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
|
|
||||||
map.register(float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
|
|
||||||
map.register(Integer.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
|
|
||||||
map.register(int.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
|
|
||||||
map.register(Long.class, wrapDeserializer(LONG_DESERIALIZER));
|
|
||||||
map.register(long.class, wrapDeserializer(LONG_DESERIALIZER));
|
|
||||||
map.register(Number.class, wrapDeserializer(NUMBER_TYPE_ADAPTER));
|
|
||||||
map.register(Short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
|
|
||||||
map.register(short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
|
|
||||||
map.register(String.class, wrapDeserializer(STRING_TYPE_ADAPTER));
|
|
||||||
|
|
||||||
map.makeUnmodifiable();
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() {
|
|
||||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
|
||||||
new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
|
||||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
|
|
||||||
|
|
||||||
// Add Collection type instance creators
|
|
||||||
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
|
|
||||||
|
|
||||||
map.registerForTypeHierarchy(Set.class, HASH_SET_CREATOR);
|
|
||||||
map.registerForTypeHierarchy(SortedSet.class, TREE_SET_CREATOR);
|
|
||||||
map.register(Properties.class, PROPERTIES_CREATOR);
|
|
||||||
map.makeUnmodifiable();
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
private static JsonDeserializer<?> wrapDeserializer(JsonDeserializer<?> deserializer) {
|
|
||||||
return new JsonDeserializerExceptionWrapper(deserializer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers() {
|
|
||||||
return getDefaultSerializers(false, LongSerializationPolicy.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers(
|
|
||||||
boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) {
|
|
||||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers =
|
|
||||||
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
|
||||||
|
|
||||||
// Double primitive
|
|
||||||
DefaultTypeAdapters.DoubleSerializer doubleSerializer =
|
|
||||||
new DefaultTypeAdapters.DoubleSerializer(serializeSpecialFloatingPointValues);
|
|
||||||
serializers.registerIfAbsent(Double.class, doubleSerializer);
|
|
||||||
serializers.registerIfAbsent(double.class, doubleSerializer);
|
|
||||||
|
|
||||||
// Float primitive
|
|
||||||
DefaultTypeAdapters.FloatSerializer floatSerializer =
|
|
||||||
new DefaultTypeAdapters.FloatSerializer(serializeSpecialFloatingPointValues);
|
|
||||||
serializers.registerIfAbsent(Float.class, floatSerializer);
|
|
||||||
serializers.registerIfAbsent(float.class, floatSerializer);
|
|
||||||
|
|
||||||
// Long primitive
|
|
||||||
DefaultTypeAdapters.LongSerializer longSerializer =
|
|
||||||
new DefaultTypeAdapters.LongSerializer(longSerializationPolicy);
|
|
||||||
serializers.registerIfAbsent(Long.class, longSerializer);
|
|
||||||
serializers.registerIfAbsent(long.class, longSerializer);
|
|
||||||
|
|
||||||
serializers.registerIfAbsent(DEFAULT_SERIALIZERS);
|
|
||||||
return serializers;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParameterizedTypeHandlerMap<JsonDeserializer<?>> getDefaultDeserializers() {
|
|
||||||
return DEFAULT_DESERIALIZERS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ParameterizedTypeHandlerMap<InstanceCreator<?>> getDefaultInstanceCreators() {
|
|
||||||
return DEFAULT_INSTANCE_CREATORS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
|
|
||||||
private final DateFormat format;
|
|
||||||
|
|
||||||
DefaultDateTypeAdapter() {
|
|
||||||
this.format = DateFormat.getDateTimeInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultDateTypeAdapter(final String datePattern) {
|
|
||||||
this.format = new SimpleDateFormat(datePattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultDateTypeAdapter(final int style) {
|
|
||||||
this.format = DateFormat.getDateInstance(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DefaultDateTypeAdapter(final int dateStyle, final int timeStyle) {
|
|
||||||
this.format = DateFormat.getDateTimeInstance(dateStyle, timeStyle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// These methods need to be synchronized since JDK DateFormat classes are not thread-safe
|
|
||||||
// See issue 162
|
|
||||||
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
synchronized (format) {
|
|
||||||
String dateFormatAsString = format.format(src);
|
|
||||||
return new JsonPrimitive(dateFormatAsString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
if (!(json instanceof JsonPrimitive)) {
|
|
||||||
throw new JsonParseException("The date should be a string value");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
synchronized (format) {
|
|
||||||
return format.parse(json.getAsString());
|
|
||||||
}
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(DefaultDateTypeAdapter.class.getSimpleName());
|
|
||||||
sb.append('(').append(format.getClass().getSimpleName()).append(')');
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>,
|
|
||||||
JsonDeserializer<java.sql.Date> {
|
|
||||||
private final DateFormat format;
|
|
||||||
DefaultJavaSqlDateTypeAdapter() {
|
|
||||||
this.format = new SimpleDateFormat("MMM d, yyyy");
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonElement serialize(java.sql.Date src, Type typeOfSrc,
|
|
||||||
JsonSerializationContext context) {
|
|
||||||
synchronized (format) {
|
|
||||||
String dateFormatAsString = format.format(src);
|
|
||||||
return new JsonPrimitive(dateFormatAsString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public java.sql.Date deserialize(JsonElement json, Type typeOfT,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
if (!(json instanceof JsonPrimitive)) {
|
|
||||||
throw new JsonParseException("The date should be a string value");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
synchronized (format) {
|
|
||||||
Date date = format.parse(json.getAsString());
|
|
||||||
return new java.sql.Date(date.getTime());
|
|
||||||
}
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class DefaultTimestampDeserializer implements JsonDeserializer<Timestamp> {
|
|
||||||
public Timestamp deserialize(JsonElement json, Type typeOfT,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
Date date = context.deserialize(json, Date.class);
|
|
||||||
return new Timestamp(date.getTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class DefaultTimeTypeAdapter implements JsonSerializer<Time>, JsonDeserializer<Time> {
|
|
||||||
private final DateFormat format;
|
|
||||||
DefaultTimeTypeAdapter() {
|
|
||||||
this.format = new SimpleDateFormat("hh:mm:ss a");
|
|
||||||
}
|
|
||||||
public JsonElement serialize(Time src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
synchronized (format) {
|
|
||||||
String dateFormatAsString = format.format(src);
|
|
||||||
return new JsonPrimitive(dateFormatAsString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Time deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
if (!(json instanceof JsonPrimitive)) {
|
|
||||||
throw new JsonParseException("The date should be a string value");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
synchronized (format) {
|
|
||||||
Date date = format.parse(json.getAsString());
|
|
||||||
return new Time(date.getTime());
|
|
||||||
}
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class GregorianCalendarTypeAdapter
|
|
||||||
implements JsonSerializer<GregorianCalendar>, JsonDeserializer<GregorianCalendar> {
|
|
||||||
|
|
||||||
private static final String YEAR = "year";
|
|
||||||
private static final String MONTH = "month";
|
|
||||||
private static final String DAY_OF_MONTH = "dayOfMonth";
|
|
||||||
private static final String HOUR_OF_DAY = "hourOfDay";
|
|
||||||
private static final String MINUTE = "minute";
|
|
||||||
private static final String SECOND = "second";
|
|
||||||
|
|
||||||
public JsonElement serialize(GregorianCalendar src, Type typeOfSrc,
|
|
||||||
JsonSerializationContext context) {
|
|
||||||
JsonObject obj = new JsonObject();
|
|
||||||
obj.addProperty(YEAR, src.get(Calendar.YEAR));
|
|
||||||
obj.addProperty(MONTH, src.get(Calendar.MONTH));
|
|
||||||
obj.addProperty(DAY_OF_MONTH, src.get(Calendar.DAY_OF_MONTH));
|
|
||||||
obj.addProperty(HOUR_OF_DAY, src.get(Calendar.HOUR_OF_DAY));
|
|
||||||
obj.addProperty(MINUTE, src.get(Calendar.MINUTE));
|
|
||||||
obj.addProperty(SECOND, src.get(Calendar.SECOND));
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GregorianCalendar deserialize(JsonElement json, Type typeOfT,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
JsonObject obj = json.getAsJsonObject();
|
|
||||||
int year = obj.get(YEAR).getAsInt();
|
|
||||||
int month = obj.get(MONTH).getAsInt();
|
|
||||||
int dayOfMonth = obj.get(DAY_OF_MONTH).getAsInt();
|
|
||||||
int hourOfDay = obj.get(HOUR_OF_DAY).getAsInt();
|
|
||||||
int minute = obj.get(MINUTE).getAsInt();
|
|
||||||
int second = obj.get(SECOND).getAsInt();
|
|
||||||
return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return GregorianCalendarTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static class EnumTypeAdapter<T extends Enum<T>>
|
|
||||||
implements JsonSerializer<T>, JsonDeserializer<T> {
|
|
||||||
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("cast")
|
|
||||||
public T deserialize(JsonElement json, Type classOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return (T) Enum.valueOf((Class<T>) classOfT, json.getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return EnumTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class UrlTypeAdapter implements JsonSerializer<URL>, JsonDeserializer<URL> {
|
|
||||||
public JsonElement serialize(URL src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src.toExternalForm());
|
|
||||||
}
|
|
||||||
|
|
||||||
public URL deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
try {
|
|
||||||
return new URL(json.getAsString());
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return UrlTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class UriTypeAdapter implements JsonSerializer<URI>, JsonDeserializer<URI> {
|
|
||||||
public JsonElement serialize(URI src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src.toASCIIString());
|
|
||||||
}
|
|
||||||
public URI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
try {
|
|
||||||
return new URI(json.getAsString());
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return UriTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class UuidTypeAdapter implements JsonSerializer<UUID>, JsonDeserializer<UUID> {
|
|
||||||
public JsonElement serialize(UUID src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return UUID.fromString(json.getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return UuidTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class LocaleTypeAdapter
|
|
||||||
implements JsonSerializer<Locale>, JsonDeserializer<Locale> {
|
|
||||||
public JsonElement serialize(Locale src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Locale deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
String locale = json.getAsString();
|
|
||||||
StringTokenizer tokenizer = new StringTokenizer(locale, "_");
|
|
||||||
String language = null;
|
|
||||||
String country = null;
|
|
||||||
String variant = null;
|
|
||||||
if (tokenizer.hasMoreElements()) {
|
|
||||||
language = tokenizer.nextToken();
|
|
||||||
}
|
|
||||||
if (tokenizer.hasMoreElements()) {
|
|
||||||
country = tokenizer.nextToken();
|
|
||||||
}
|
|
||||||
if (tokenizer.hasMoreElements()) {
|
|
||||||
variant = tokenizer.nextToken();
|
|
||||||
}
|
|
||||||
if (country == null && variant == null) {
|
|
||||||
return new Locale(language);
|
|
||||||
} else if (variant == null) {
|
|
||||||
return new Locale(language, country);
|
|
||||||
} else {
|
|
||||||
return new Locale(language, country, variant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return LocaleTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
private static class CollectionTypeAdapter implements JsonSerializer<Collection>,
|
|
||||||
JsonDeserializer<Collection>, InstanceCreator<Collection> {
|
|
||||||
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
if (src == null) {
|
|
||||||
return JsonNull.createJsonNull();
|
|
||||||
}
|
|
||||||
JsonArray array = new JsonArray();
|
|
||||||
Type childGenericType = null;
|
|
||||||
if (typeOfSrc instanceof ParameterizedType) {
|
|
||||||
childGenericType = new TypeInfoCollection(typeOfSrc).getElementType();
|
|
||||||
}
|
|
||||||
for (Object child : src) {
|
|
||||||
if (child == null) {
|
|
||||||
array.add(JsonNull.createJsonNull());
|
|
||||||
} else {
|
|
||||||
Type childType = (childGenericType == null || childGenericType == Object.class)
|
|
||||||
? child.getClass() : childGenericType;
|
|
||||||
JsonElement element = context.serialize(child, childType);
|
|
||||||
array.add(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection deserialize(JsonElement json, Type typeOfT,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
if (json.isJsonNull()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
|
|
||||||
// This handles cases where users are using their own subclass of Collection.
|
|
||||||
Collection collection = constructCollectionType(typeOfT, context);
|
|
||||||
Type childType = new TypeInfoCollection(typeOfT).getElementType();
|
|
||||||
for (JsonElement childElement : json.getAsJsonArray()) {
|
|
||||||
if (childElement == null || childElement.isJsonNull()) {
|
|
||||||
collection.add(null);
|
|
||||||
} else {
|
|
||||||
Object value = context.deserialize(childElement, childType);
|
|
||||||
collection.add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection constructCollectionType(Type collectionType,
|
|
||||||
JsonDeserializationContext context) {
|
|
||||||
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
|
|
||||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
|
||||||
return (Collection) objectConstructor.construct(collectionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection createInstance(Type type) {
|
|
||||||
return new LinkedList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PropertiesCreator implements InstanceCreator<Properties> {
|
|
||||||
public Properties createInstance(Type type) {
|
|
||||||
return new Properties();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
static class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>,
|
|
||||||
InstanceCreator<Map> {
|
|
||||||
|
|
||||||
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
JsonObject map = new JsonObject();
|
|
||||||
Type childGenericType = null;
|
|
||||||
if (typeOfSrc instanceof ParameterizedType) {
|
|
||||||
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
|
|
||||||
Object value = entry.getValue();
|
|
||||||
|
|
||||||
JsonElement valueElement;
|
|
||||||
if (value == null) {
|
|
||||||
valueElement = JsonNull.createJsonNull();
|
|
||||||
} else {
|
|
||||||
Type childType = (childGenericType == null)
|
|
||||||
? value.getClass() : childGenericType;
|
|
||||||
valueElement = context.serialize(value, childType);
|
|
||||||
}
|
|
||||||
map.add(String.valueOf(entry.getKey()), valueElement);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
|
|
||||||
// This handles cases where users are using their own subclass of Map.
|
|
||||||
Map<Object, Object> map = constructMapType(typeOfT, context);
|
|
||||||
TypeInfoMap mapTypeInfo = new TypeInfoMap(typeOfT);
|
|
||||||
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
|
|
||||||
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), mapTypeInfo.getKeyType());
|
|
||||||
Object value = context.deserialize(entry.getValue(), mapTypeInfo.getValueType());
|
|
||||||
map.put(key, value);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map constructMapType(Type mapType, JsonDeserializationContext context) {
|
|
||||||
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
|
|
||||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
|
||||||
return (Map) objectConstructor.construct(mapType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map createInstance(Type type) {
|
|
||||||
return new LinkedHashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return MapTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class BigDecimalTypeAdapter
|
|
||||||
implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> {
|
|
||||||
public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigDecimal deserialize(JsonElement json, Type typeOfT,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
return json.getAsBigDecimal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return BigDecimalTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class BigIntegerTypeAdapter
|
|
||||||
implements JsonSerializer<BigInteger>, JsonDeserializer<BigInteger> {
|
|
||||||
|
|
||||||
public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger deserialize(JsonElement json, Type typeOfT,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
return json.getAsBigInteger();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return BigIntegerTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class NumberTypeAdapter
|
|
||||||
implements JsonSerializer<Number>, JsonDeserializer<Number> {
|
|
||||||
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return NumberTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class LongSerializer implements JsonSerializer<Long> {
|
|
||||||
private final LongSerializationPolicy longSerializationPolicy;
|
|
||||||
|
|
||||||
private LongSerializer(LongSerializationPolicy longSerializationPolicy) {
|
|
||||||
this.longSerializationPolicy = longSerializationPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return longSerializationPolicy.serialize(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return LongSerializer.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class LongDeserializer implements JsonDeserializer<Long> {
|
|
||||||
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return LongDeserializer.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class IntegerTypeAdapter
|
|
||||||
implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
|
|
||||||
public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return IntegerTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ShortTypeAdapter
|
|
||||||
implements JsonSerializer<Short>, JsonDeserializer<Short> {
|
|
||||||
public JsonElement serialize(Short src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Short deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsShort();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return ShortTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ByteTypeAdapter implements JsonSerializer<Byte>, JsonDeserializer<Byte> {
|
|
||||||
public JsonElement serialize(Byte src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return ByteTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class FloatSerializer implements JsonSerializer<Float> {
|
|
||||||
private final boolean serializeSpecialFloatingPointValues;
|
|
||||||
|
|
||||||
FloatSerializer(boolean serializeSpecialDoubleValues) {
|
|
||||||
this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonElement serialize(Float src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
if (!serializeSpecialFloatingPointValues) {
|
|
||||||
if (Float.isNaN(src) || Float.isInfinite(src)) {
|
|
||||||
throw new IllegalArgumentException(src
|
|
||||||
+ " is not a valid float value as per JSON specification. To override this"
|
|
||||||
+ " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class FloatDeserializer implements JsonDeserializer<Float> {
|
|
||||||
public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return FloatDeserializer.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class DoubleSerializer implements JsonSerializer<Double> {
|
|
||||||
private final boolean serializeSpecialFloatingPointValues;
|
|
||||||
|
|
||||||
DoubleSerializer(boolean serializeSpecialDoubleValues) {
|
|
||||||
this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
if (!serializeSpecialFloatingPointValues) {
|
|
||||||
if (Double.isNaN(src) || Double.isInfinite(src)) {
|
|
||||||
throw new IllegalArgumentException(src
|
|
||||||
+ " is not a valid double value as per JSON specification. To override this"
|
|
||||||
+ " behavior, use GsonBuilder.serializeSpecialDoubleValues() method.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DoubleDeserializer implements JsonDeserializer<Double> {
|
|
||||||
public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return DoubleDeserializer.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CharacterTypeAdapter
|
|
||||||
implements JsonSerializer<Character>, JsonDeserializer<Character> {
|
|
||||||
public JsonElement serialize(Character src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Character deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsCharacter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return CharacterTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class StringTypeAdapter
|
|
||||||
implements JsonSerializer<String>, JsonDeserializer<String> {
|
|
||||||
public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return StringTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class BooleanTypeAdapter
|
|
||||||
implements JsonSerializer<Boolean>, JsonDeserializer<Boolean> {
|
|
||||||
public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
return json.getAsBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return BooleanTypeAdapter.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TreeSetCreator implements InstanceCreator<TreeSet<?>> {
|
|
||||||
public TreeSet<?> createInstance(Type type) {
|
|
||||||
return new TreeSet<Object>();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return TreeSetCreator.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class HashSetCreator implements InstanceCreator<HashSet<?>> {
|
|
||||||
public HashSet<?> createInstance(Type type) {
|
|
||||||
return new HashSet<Object>();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return HashSetCreator.class.getSimpleName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple implementation of the {@link JsonElementVisitor} that simply delegates the method
|
|
||||||
* invocation onto a {@code delegate} instance of the {@link JsonElementVisitor}. This object
|
|
||||||
* can be used to build a chain of visitors such that each Visitor instance can perform some
|
|
||||||
* operation on the {@link JsonElement} and then pass on the input to the delegate. This kind
|
|
||||||
* of pattern is sometimes referred as a "Chain of Responsibility".
|
|
||||||
*
|
|
||||||
* <p>The following is an example use case:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* class JsonEscapingVisitor extends DelegatingJsonElementVisitor {
|
|
||||||
* public JsonEscapingVisitor(JsonElementVisitor) {
|
|
||||||
* super(visitor);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public void visitPrimitive(JsonPrimitive primitive) {
|
|
||||||
* JsonPrimitive escapedPrimitive = escapePrimitiveObject(primitive);
|
|
||||||
* super.visitPrimitive(escapedPrimitive);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* JsonElementVisitor visitor = new JsonEscapingVisitor(new FormattingVisitor());
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<ExclusionStrategy> strategies;
|
|
||||||
|
|
||||||
public DisjunctionExclusionStrategy(Collection<ExclusionStrategy> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>This class contains a single method to escape a passed in string value:
|
|
||||||
* <pre>
|
|
||||||
* String jsonStringValue = "beforeQuote\"afterQuote";
|
|
||||||
* String escapedValue = Escaper.escapeJsonString(jsonStringValue);
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* @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<Character> JS_ESCAPE_CHARS;
|
|
||||||
private static final Set<Character> HTML_ESCAPE_CHARS;
|
|
||||||
|
|
||||||
static {
|
|
||||||
Set<Character> mandatoryEscapeSet = new HashSet<Character>();
|
|
||||||
mandatoryEscapeSet.add('"');
|
|
||||||
mandatoryEscapeSet.add('\\');
|
|
||||||
JS_ESCAPE_CHARS = Collections.unmodifiableSet(mandatoryEscapeSet);
|
|
||||||
|
|
||||||
Set<Character> htmlEscapeSet = new HashSet<Character>();
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>The following are a few examples that shows how you can use this exclusion mechanism.
|
|
||||||
*
|
|
||||||
* <p><strong>Exclude fields and objects based on a particular class type:</strong>
|
|
||||||
* <pre class="code">
|
|
||||||
* private static class SpecificClassExclusionStrategy implements ExclusionStrategy {
|
|
||||||
* private final Class<?> excludedThisClass;
|
|
||||||
*
|
|
||||||
* public SpecificClassExclusionStrategy(Class<?> excludedThisClass) {
|
|
||||||
* this.excludedThisClass = excludedThisClass;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public boolean shouldSkipClass(Class<?> clazz) {
|
|
||||||
* return excludedThisClass.equals(clazz);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public boolean shouldSkipField(FieldAttributes f) {
|
|
||||||
* return excludedThisClass.equals(f.getDeclaredClass());
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p><strong>Excludes fields and objects based on a particular annotation:</strong>
|
|
||||||
* <pre class="code">
|
|
||||||
* public @interface FooAnnotation {
|
|
||||||
* // some implementation here
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // Excludes any field (or class) that is tagged with an "@FooAnnotation"
|
|
||||||
* private static class FooAnnotationExclusionStrategy implements ExclusionStrategy {
|
|
||||||
* public boolean shouldSkipClass(Class<?> clazz) {
|
|
||||||
* return clazz.getAnnotation(FooAnnotation.class) != null;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public boolean shouldSkipField(FieldAttributes f) {
|
|
||||||
* return f.getAnnotation(FooAnnotation.class) != null;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>Now if you want to configure {@code Gson} to use a user defined exclusion strategy, then
|
|
||||||
* the {@code GsonBuilder} is required. The following is an example of how you can use the
|
|
||||||
* {@code GsonBuilder} to configure Gson to use one of the above sample:
|
|
||||||
* <pre class="code">
|
|
||||||
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
|
|
||||||
* Gson gson = new GsonBuilder()
|
|
||||||
* .setExclusionStrategies(excludeStrings)
|
|
||||||
* .create();
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
-39
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>This class is immutable; therefore, it can be safely shared across threads.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*
|
|
||||||
* @since 1.4
|
|
||||||
*/
|
|
||||||
public final class FieldAttributes {
|
|
||||||
private static final String MAX_CACHE_PROPERTY_NAME =
|
|
||||||
"com.bukkit.mcteam.gson.annotation_cache_size_hint";
|
|
||||||
|
|
||||||
private static final Cache<Pair<Class<?>, String>, Collection<Annotation>> ANNOTATION_CACHE =
|
|
||||||
new LruCache<Pair<Class<?>,String>, Collection<Annotation>>(getMaxCacheSize());
|
|
||||||
|
|
||||||
private final Class<?> declaringClazz;
|
|
||||||
private final Field field;
|
|
||||||
private final Class<?> declaredType;
|
|
||||||
private final boolean isSynthetic;
|
|
||||||
private final int modifiers;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
// Fields used for lazy initialization
|
|
||||||
private Type genericType;
|
|
||||||
private Collection<Annotation> annotations;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a Field Attributes object from the {@code f}.
|
|
||||||
*
|
|
||||||
* @param f the field to pull attributes from
|
|
||||||
*/
|
|
||||||
FieldAttributes(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>For example, assume the following class definition:
|
|
||||||
* <pre class="code">
|
|
||||||
* public class Foo {
|
|
||||||
* private String bar;
|
|
||||||
* private List<String> red;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Type listParmeterizedType = new TypeToken<List<String>>() {}.getType();
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>This method would return {@code String.class} for the {@code bar} field and
|
|
||||||
* {@code listParameterizedType} for the {@code red} field.
|
|
||||||
*
|
|
||||||
* @return the specific type declared for this field
|
|
||||||
*/
|
|
||||||
public Type getDeclaredType() {
|
|
||||||
if (genericType == null) {
|
|
||||||
genericType = field.getGenericType();
|
|
||||||
}
|
|
||||||
return genericType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@code Class<?>} object that was declared for this field.
|
|
||||||
*
|
|
||||||
* <p>For example, assume the following class definition:
|
|
||||||
* <pre class="code">
|
|
||||||
* public class Foo {
|
|
||||||
* private String bar;
|
|
||||||
* private List<String> red;
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>This method would return {@code String.class} for the {@code bar} field and
|
|
||||||
* {@code List.class} for the {@code red} field.
|
|
||||||
*
|
|
||||||
* @return the specific class object that was declared for the field
|
|
||||||
*/
|
|
||||||
public Class<?> getDeclaredClass() {
|
|
||||||
return 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 extends Annotation> T getAnnotation(Class<T> 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<Annotation> getAnnotations() {
|
|
||||||
if (annotations == null) {
|
|
||||||
Pair<Class<?>, String> key = new Pair<Class<?>, 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}.
|
|
||||||
*
|
|
||||||
* <p>This method is meant to be called as:
|
|
||||||
* <pre class="code">
|
|
||||||
* boolean hasPublicModifier = fieldAttribute.hasModifier(java.lang.reflect.Modifier.PUBLIC);
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @see java.lang.reflect.Modifier
|
|
||||||
*/
|
|
||||||
public boolean hasModifier(int modifier) {
|
|
||||||
return (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 extends Annotation> T getAnnotationFromArray(
|
|
||||||
Collection<Annotation> annotations, Class<T> annotation) {
|
|
||||||
for (Annotation a : annotations) {
|
|
||||||
if (a.annotationType() == annotation) {
|
|
||||||
return (T) a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
|
||||||
* <ul>
|
|
||||||
* <li>someFieldName ---> SomeFieldName</li>
|
|
||||||
* <li>_someFieldName ---> _SomeFieldName</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
UPPER_CAMEL_CASE(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.
|
|
||||||
*
|
|
||||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
|
||||||
* <ul>
|
|
||||||
* <li>someFieldName ---> Some Field Name</li>
|
|
||||||
* <li>_someFieldName ---> _Some Field Name</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @since 1.4
|
|
||||||
*/
|
|
||||||
UPPER_CAMEL_CASE_WITH_SPACES(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 (_).
|
|
||||||
*
|
|
||||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
|
||||||
* <ul>
|
|
||||||
* <li>someFieldName ---> some_field_name</li>
|
|
||||||
* <li>_someFieldName ---> _some_field_name</li>
|
|
||||||
* <li>aStringField ---> a_string_field</li>
|
|
||||||
* <li>aURL ---> a_u_r_l</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
LOWER_CASE_WITH_UNDERSCORES(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 (-).
|
|
||||||
*
|
|
||||||
* <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
|
|
||||||
* <ul>
|
|
||||||
* <li>someFieldName ---> some-field-name</li>
|
|
||||||
* <li>_someFieldName ---> _some-field-name</li>
|
|
||||||
* <li>aStringField ---> a-string-field</li>
|
|
||||||
* <li>aURL ---> a-u-r-l</li>
|
|
||||||
* </ul>
|
|
||||||
* Using dashes in JavaScript is not recommended since dash is also used for a minus sign in
|
|
||||||
* expressions. This requires that a field named with dashes is always accessed as a quoted
|
|
||||||
* property like {@code myobject['my-field']}. Accessing it as an object field
|
|
||||||
* {@code myobject.my-field} will result in an unintended javascript expression.
|
|
||||||
* @since 1.4
|
|
||||||
*/
|
|
||||||
LOWER_CASE_WITH_DASHES(new LowerCamelCaseSeparatorNamingPolicy("-"));
|
|
||||||
|
|
||||||
private final FieldNamingStrategy2 namingPolicy;
|
|
||||||
|
|
||||||
private FieldNamingPolicy(FieldNamingStrategy2 namingPolicy) {
|
|
||||||
this.namingPolicy = namingPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldNamingStrategy2 getFieldNamingPolicy() {
|
|
||||||
return namingPolicy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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:
|
|
||||||
* <pre>
|
|
||||||
* class Foo<T> {
|
|
||||||
* private final List<T>[] arrayOfListT;
|
|
||||||
*
|
|
||||||
* Foo(List<T>[] arrayList) {
|
|
||||||
* this.arrayOfListT = arrayList;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,597 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>You can create a Gson instance by invoking {@code new Gson()} if the default configuration
|
|
||||||
* is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various
|
|
||||||
* configuration options such as versioning support, pretty printing, custom
|
|
||||||
* {@link JsonSerializer}s, {@link JsonDeserializer}s, and {@link InstanceCreator}s.</p>
|
|
||||||
*
|
|
||||||
* <p>Here is an example of how Gson is used for a simple Class:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Gson gson = new Gson(); // Or use new GsonBuilder().create();
|
|
||||||
* MyType target = new MyType();
|
|
||||||
* String json = gson.toJson(target); // serializes target to Json
|
|
||||||
* MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* <p>If the object that your are serializing/deserializing is a {@code ParameterizedType}
|
|
||||||
* (i.e. contains at least one type parameter and may be an array) then you must use the
|
|
||||||
* {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Here is an
|
|
||||||
* example for serializing and deserialing a {@code ParameterizedType}:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Type listType = new TypeToken<List<String>>() {}.getType();
|
|
||||||
* List<String> target = new LinkedList<String>();
|
|
||||||
* target.add("blah");
|
|
||||||
*
|
|
||||||
* Gson gson = new Gson();
|
|
||||||
* String json = gson.toJson(target, listType);
|
|
||||||
* List<String> target2 = gson.fromJson(json, listType);
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* <p>See the <a href="https://sites.google.com/site/gson/gson-user-guide">Gson User Guide</a>
|
|
||||||
* for a more complete set of examples.</p>
|
|
||||||
*
|
|
||||||
* @see 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<JsonSerializer<?>> serializers;
|
|
||||||
|
|
||||||
/** Map containing Type or Class objects as keys */
|
|
||||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
|
||||||
|
|
||||||
private final boolean serializeNulls;
|
|
||||||
private final boolean htmlSafe;
|
|
||||||
private final boolean generateNonExecutableJson;
|
|
||||||
private final boolean prettyPrinting;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a Gson object with default configuration. The default configuration has the
|
|
||||||
* following settings:
|
|
||||||
* <ul>
|
|
||||||
* <li>The JSON generated by <code>toJson</code> methods is in compact representation. This
|
|
||||||
* means that all the unneeded white-space is removed. You can change this behavior with
|
|
||||||
* {@link GsonBuilder#setPrettyPrinting()}. </li>
|
|
||||||
* <li>The generated JSON omits all the fields that are null. Note that nulls in arrays are
|
|
||||||
* kept as is since an array is an ordered list. Moreover, if a field is not null, but its
|
|
||||||
* generated JSON is empty, the field is kept. You can configure Gson to serialize null values
|
|
||||||
* by setting {@link GsonBuilder#serializeNulls()}.</li>
|
|
||||||
* <li>Gson provides default serialization and deserialization for Enums, {@link Map},
|
|
||||||
* {@link java.net.URL}, {@link java.net.URI}, {@link java.util.Locale}, {@link java.util.Date},
|
|
||||||
* {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer
|
|
||||||
* to change the default representation, you can do so by registering a type adapter through
|
|
||||||
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}. </li>
|
|
||||||
* <li>The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format
|
|
||||||
* ignores the millisecond portion of the date during serialization. You can change
|
|
||||||
* this by invoking {@link GsonBuilder#setDateFormat(int)} or
|
|
||||||
* {@link GsonBuilder#setDateFormat(String)}. </li>
|
|
||||||
* <li>By default, Gson ignores the {@link 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()}. </li>
|
|
||||||
* <li>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)}.</li>
|
|
||||||
* <li>The default field naming policy for the output Json is same as in Java. So, a Java class
|
|
||||||
* field <code>versionNumber</code> will be output as <code>"versionNumber@quot;</code> in
|
|
||||||
* Json. The same rules are applied for mapping incoming Json to the Java classes. You can
|
|
||||||
* change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.</li>
|
|
||||||
* <li>By default, Gson excludes <code>transient</code> or <code>static</code> fields from
|
|
||||||
* consideration for serialization and deserialization. You can change this behavior through
|
|
||||||
* {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public Gson() {
|
|
||||||
this(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<JsonSerializer<?>> serializers,
|
|
||||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> 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<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
|
|
||||||
strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
|
||||||
strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
|
||||||
strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
|
|
||||||
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<Foo>}, you should use:
|
|
||||||
* <pre>
|
|
||||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
|
||||||
* </pre>
|
|
||||||
* @return Json representation of {@code src}
|
|
||||||
* @since 1.4
|
|
||||||
*/
|
|
||||||
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
|
|
||||||
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<Foo>}, you should use:
|
|
||||||
* <pre>
|
|
||||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
|
||||||
* </pre>
|
|
||||||
* @return Json representation of {@code src}
|
|
||||||
*/
|
|
||||||
public String toJson(Object src, Type typeOfSrc) {
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
toJson(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<Foo>}, you should use:
|
|
||||||
* <pre>
|
|
||||||
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
|
||||||
* </pre>
|
|
||||||
* @param writer Writer to which the Json representation of src needs to be written.
|
|
||||||
* @throws JsonIOException if there was a problem writing to the writer
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
|
|
||||||
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 <T> the type of the desired object
|
|
||||||
* @param json the string from which the object is to be deserialized
|
|
||||||
* @param classOfT the class of T
|
|
||||||
* @return an object of type T from the string
|
|
||||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
|
||||||
* classOfT
|
|
||||||
*/
|
|
||||||
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
|
|
||||||
Object object = fromJson(json, (Type) classOfT);
|
|
||||||
return Primitives.wrap(classOfT).cast(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method deserializes the specified Json into an object of the specified type. This method
|
|
||||||
* is useful if the specified object is a generic type. For non-generic objects, use
|
|
||||||
* {@link #fromJson(String, Class)} instead. If you have the Json in a {@link Reader} instead of
|
|
||||||
* a String, use {@link #fromJson(Reader, Type)} instead.
|
|
||||||
*
|
|
||||||
* @param <T> the type of the desired object
|
|
||||||
* @param json the string from which the object is to be deserialized
|
|
||||||
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
|
||||||
* {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example, to get the type for
|
|
||||||
* {@code Collection<Foo>}, you should use:
|
|
||||||
* <pre>
|
|
||||||
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
|
||||||
* </pre>
|
|
||||||
* @return an object of type T from the string
|
|
||||||
* @throws JsonParseException if json is not a valid representation for an object of type typeOfT
|
|
||||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
|
|
||||||
if (json == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringReader reader = new StringReader(json);
|
|
||||||
T target = (T) fromJson(reader, typeOfT);
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method deserializes the Json read from the specified reader into an object of the
|
|
||||||
* specified class. It is not suitable to use if the specified class is a generic type since it
|
|
||||||
* will not have the generic type information because of the Type Erasure feature of Java.
|
|
||||||
* Therefore, this method should not be used if the desired type is a generic type. Note that
|
|
||||||
* this method works fine if the any of the fields of the specified object are generics, just the
|
|
||||||
* object itself should not be a generic type. For the cases when the object is of generic type,
|
|
||||||
* invoke {@link #fromJson(Reader, Type)}. If you have the Json in a String form instead of a
|
|
||||||
* {@link Reader}, use {@link #fromJson(String, Class)} instead.
|
|
||||||
*
|
|
||||||
* @param <T> the type of the desired object
|
|
||||||
* @param json the reader producing the Json from which the object is to be deserialized.
|
|
||||||
* @param classOfT the class of T
|
|
||||||
* @return an object of type T from the string
|
|
||||||
* @throws JsonIOException if there was a problem reading from the Reader
|
|
||||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {
|
|
||||||
JsonReader jsonReader = new JsonReader(json);
|
|
||||||
Object object = fromJson(jsonReader, classOfT);
|
|
||||||
assertFullConsumption(object, jsonReader);
|
|
||||||
return Primitives.wrap(classOfT).cast(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method deserializes the Json read from the specified reader into an object of the
|
|
||||||
* specified type. This method is useful if the specified object is a generic type. For
|
|
||||||
* non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the Json in a
|
|
||||||
* String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead.
|
|
||||||
*
|
|
||||||
* @param <T> the type of the desired object
|
|
||||||
* @param json the reader producing Json from which the object is to be deserialized
|
|
||||||
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
|
||||||
* {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example, to get the type for
|
|
||||||
* {@code Collection<Foo>}, you should use:
|
|
||||||
* <pre>
|
|
||||||
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
|
||||||
* </pre>
|
|
||||||
* @return an object of type T from the json
|
|
||||||
* @throws JsonIOException if there was a problem reading from the Reader
|
|
||||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
|
||||||
JsonReader jsonReader = new JsonReader(json);
|
|
||||||
T object = this.<T>fromJson(jsonReader, typeOfT);
|
|
||||||
assertFullConsumption(object, jsonReader);
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertFullConsumption(Object obj, JsonReader reader) {
|
|
||||||
try {
|
|
||||||
if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
|
|
||||||
throw new JsonIOException("JSON document was not fully consumed.");
|
|
||||||
}
|
|
||||||
} catch (MalformedJsonException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the next JSON value from {@code reader} and convert it to an object
|
|
||||||
* of type {@code typeOfT}.
|
|
||||||
* Since Type is not parameterized by T, this method is type unsafe and should be used carefully
|
|
||||||
*
|
|
||||||
* @throws JsonIOException if there was a problem writing to the Reader
|
|
||||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
|
||||||
boolean 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 <T> the type of the desired object
|
|
||||||
* @param json the root of the parse tree of {@link JsonElement}s from which the object is to
|
|
||||||
* be deserialized
|
|
||||||
* @param classOfT The class of T
|
|
||||||
* @return an object of type T from the json
|
|
||||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
|
|
||||||
* @since 1.3
|
|
||||||
*/
|
|
||||||
public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
|
|
||||||
Object object = fromJson(json, (Type) classOfT);
|
|
||||||
return Primitives.wrap(classOfT).cast(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method deserializes the Json read from the specified parse tree into an object of the
|
|
||||||
* specified type. This method is useful if the specified object is a generic type. For
|
|
||||||
* non-generic objects, use {@link #fromJson(JsonElement, Class)} instead.
|
|
||||||
*
|
|
||||||
* @param <T> the type of the desired object
|
|
||||||
* @param json the root of the parse tree of {@link JsonElement}s from which the object is to
|
|
||||||
* be deserialized
|
|
||||||
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
|
||||||
* {@link org.mcteam.ancientgates.gson.reflect.TypeToken} class. For example, to get the type for
|
|
||||||
* {@code Collection<Foo>}, you should use:
|
|
||||||
* <pre>
|
|
||||||
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
|
||||||
* </pre>
|
|
||||||
* @return an object of type T from the json
|
|
||||||
* @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
|
|
||||||
* @since 1.3
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
|
|
||||||
if (json == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,571 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
|
|
||||||
* options other than the default. For {@link Gson} with default configuration, it is simpler to
|
|
||||||
* use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its
|
|
||||||
* various configuration methods, and finally calling create.</p>
|
|
||||||
*
|
|
||||||
* <p>The following is an example shows how to use the {@code GsonBuilder} to construct a Gson
|
|
||||||
* instance:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Gson gson = new GsonBuilder()
|
|
||||||
* .registerTypeAdapter(Id.class, new IdTypeAdapter())
|
|
||||||
* .serializeNulls()
|
|
||||||
* .setDateFormat(DateFormat.LONG)
|
|
||||||
* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
|
|
||||||
* .setPrettyPrinting()
|
|
||||||
* .setVersion(1.0)
|
|
||||||
* .create();
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* <p>NOTE: the order of invocation of configuration methods does not matter.</p>
|
|
||||||
*
|
|
||||||
* @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<ExclusionStrategy> exclusionStrategies =
|
|
||||||
new HashSet<ExclusionStrategy>();
|
|
||||||
|
|
||||||
private double ignoreVersionsAfter;
|
|
||||||
private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy;
|
|
||||||
private boolean serializeInnerClasses;
|
|
||||||
private boolean excludeFieldsWithoutExposeAnnotation;
|
|
||||||
private LongSerializationPolicy longSerializationPolicy;
|
|
||||||
private FieldNamingStrategy2 fieldNamingPolicy;
|
|
||||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators;
|
|
||||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
|
||||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
|
||||||
private 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<InstanceCreator<?>>();
|
|
||||||
serializers = new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
|
||||||
deserializers = new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
|
||||||
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
|
|
||||||
* <a href="http://code.google.com/p/google-gson/issues/detail?id=42">Gson Issue 42</a>
|
|
||||||
* for details.
|
|
||||||
*
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.3
|
|
||||||
*/
|
|
||||||
public GsonBuilder generateNonExecutableJson() {
|
|
||||||
this.generateNonExecutableJson = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Gson to exclude all fields from consideration for serialization or deserialization
|
|
||||||
* that do not have the {@link 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.
|
|
||||||
*
|
|
||||||
* <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
|
|
||||||
* class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
|
|
||||||
* valid date and time patterns.</p>
|
|
||||||
*
|
|
||||||
* @param pattern the pattern that dates will be serialized/deserialized to/from
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public GsonBuilder setDateFormat(String pattern) {
|
|
||||||
// TODO(Joel): Make this fail fast if it is an invalid date format
|
|
||||||
this.datePattern = pattern;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Gson to to serialize {@code Date} objects according to the style value provided.
|
|
||||||
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
|
|
||||||
* invocation will be used to decide the serialization format.
|
|
||||||
*
|
|
||||||
* <p>Note that this style value should be one of the predefined constants in the
|
|
||||||
* {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
|
|
||||||
* information on the valid style constants.</p>
|
|
||||||
*
|
|
||||||
* @param style the predefined date style that date objects will be serialized/deserialized
|
|
||||||
* to/from
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public GsonBuilder setDateFormat(int style) {
|
|
||||||
this.dateStyle = style;
|
|
||||||
this.datePattern = null;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Gson to to serialize {@code Date} objects according to the style value provided.
|
|
||||||
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
|
|
||||||
* invocation will be used to decide the serialization format.
|
|
||||||
*
|
|
||||||
* <p>Note that this style value should be one of the predefined constants in the
|
|
||||||
* {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
|
|
||||||
* information on the valid style constants.</p>
|
|
||||||
*
|
|
||||||
* @param dateStyle the predefined date style that date objects will be serialized/deserialized
|
|
||||||
* to/from
|
|
||||||
* @param timeStyle the predefined style for the time portion of the date objects
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public GsonBuilder setDateFormat(int dateStyle, int timeStyle) {
|
|
||||||
this.dateStyle = dateStyle;
|
|
||||||
this.timeStyle = timeStyle;
|
|
||||||
this.datePattern = null;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Gson for custom serialization or deserialization. This method combines the
|
|
||||||
* registration of an {@link 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 <T> the type for which instance creator is being registered
|
|
||||||
* @param typeOfT The Type definition for T
|
|
||||||
* @param instanceCreator the instance creator for T
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
*/
|
|
||||||
private <T> 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 <T> the type for which the serializer is being registered
|
|
||||||
* @param typeOfT The type definition for T
|
|
||||||
* @param serializer the custom serializer
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
*/
|
|
||||||
private <T> GsonBuilder registerSerializer(Type typeOfT, final JsonSerializer<T> 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 <T> the type for which the deserializer is being registered
|
|
||||||
* @param typeOfT The type definition for T
|
|
||||||
* @param deserializer the custom deserializer
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
*/
|
|
||||||
private <T> GsonBuilder registerDeserializer(Type typeOfT, JsonDeserializer<T> deserializer) {
|
|
||||||
deserializers.register(typeOfT, new JsonDeserializerExceptionWrapper<T>(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 <T> GsonBuilder registerInstanceCreatorForTypeHierarchy(Class<?> classOfT,
|
|
||||||
InstanceCreator<? extends T> instanceCreator) {
|
|
||||||
instanceCreators.registerForTypeHierarchy(classOfT, instanceCreator);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> GsonBuilder registerSerializerForTypeHierarchy(Class<?> classOfT,
|
|
||||||
final JsonSerializer<T> serializer) {
|
|
||||||
serializers.registerForTypeHierarchy(classOfT, serializer);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> GsonBuilder registerDeserializerForTypeHierarchy(Class<?> classOfT,
|
|
||||||
JsonDeserializer<T> deserializer) {
|
|
||||||
deserializers.registerForTypeHierarchy(classOfT,
|
|
||||||
new JsonDeserializerExceptionWrapper<T>(deserializer));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Section 2.4 of <a href="http://www.ietf.org/rfc/rfc4627.txt">JSON specification</a> disallows
|
|
||||||
* special double values (NaN, Infinity, -Infinity). However,
|
|
||||||
* <a href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf">Javascript
|
|
||||||
* specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
|
|
||||||
* values. Moreover, most JavaScript engines will accept these special values in JSON without
|
|
||||||
* problem. So, at a practical level, it makes sense to accept these values as valid JSON even
|
|
||||||
* though JSON specification disallows them.
|
|
||||||
*
|
|
||||||
* <p>Gson always accepts these special values during deserialization. However, it outputs
|
|
||||||
* strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},
|
|
||||||
* {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value
|
|
||||||
* {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it
|
|
||||||
* will throw an {@link IllegalArgumentException}. This method provides a way to override the
|
|
||||||
* default behavior when you know that the JSON receiver will be able to handle these special
|
|
||||||
* values.
|
|
||||||
*
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.3
|
|
||||||
*/
|
|
||||||
public GsonBuilder serializeSpecialFloatingPointValues() {
|
|
||||||
this.serializeSpecialFloatingPointValues = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a {@link Gson} instance based on the current configuration. This method is free of
|
|
||||||
* side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.
|
|
||||||
*
|
|
||||||
* @return an instance of Gson configured with the options currently set in this builder
|
|
||||||
*/
|
|
||||||
public Gson create() {
|
|
||||||
List<ExclusionStrategy> serializationStrategies =
|
|
||||||
new LinkedList<ExclusionStrategy>(exclusionStrategies);
|
|
||||||
List<ExclusionStrategy> deserializationStrategies =
|
|
||||||
new LinkedList<ExclusionStrategy>(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<JsonSerializer<?>> customSerializers = serializers.copyOf();
|
|
||||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> customDeserializers = deserializers.copyOf();
|
|
||||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers,
|
|
||||||
customDeserializers);
|
|
||||||
|
|
||||||
customSerializers.registerIfAbsent(DefaultTypeAdapters.getDefaultSerializers(
|
|
||||||
serializeSpecialFloatingPointValues, longSerializationPolicy));
|
|
||||||
|
|
||||||
customDeserializers.registerIfAbsent(DefaultTypeAdapters.getDefaultDeserializers());
|
|
||||||
|
|
||||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> 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<JsonSerializer<?>> serializers,
|
|
||||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
* <p>Let us look at an example where defining an InstanceCreator might be useful. The
|
|
||||||
* {@code Id} class defined below does not have a default no-args constructor.</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* public class Id<T> {
|
|
||||||
* private final Class<T> clazz;
|
|
||||||
* private final long value;
|
|
||||||
* public Id(Class<T> clazz, long value) {
|
|
||||||
* this.clazz = clazz;
|
|
||||||
* this.value = value;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>If Gson encounters an object of type {@code Id} during deserialization, it will throw an
|
|
||||||
* exception. The easiest way to solve this problem will be to add a (public or private) no-args
|
|
||||||
* constructor as follows:</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* private Id() {
|
|
||||||
* this(Object.class, 0L);
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>However, let us assume that the developer does not have access to the source-code of the
|
|
||||||
* {@code Id} class, or does not want to define a no-args constructor for it. The developer
|
|
||||||
* can solve this problem by defining an {@code InstanceCreator} for {@code Id}:</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* class IdInstanceCreator implements InstanceCreator<Id> {
|
|
||||||
* public Id createInstance(Type type) {
|
|
||||||
* return new Id(Object.class, 0L);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>Note that it does not matter what the fields of the created instance contain since Gson will
|
|
||||||
* overwrite them with the deserialized values specified in Json. You should also ensure that a
|
|
||||||
* <i>new</i> object is returned, not a common object since its fields will be overwritten.
|
|
||||||
* The developer will need to register {@code IdInstanceCreator} with Gson as follows:</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdInstanceCreator()).create();
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param <T> the type of object that will be created by this implementation.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
public interface InstanceCreator<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gson invokes this call-back method during deserialization to create an instance of the
|
|
||||||
* specified type. The fields of the returned instance are overwritten with the data present
|
|
||||||
* in the Json. Since the prior contents of the object are destroyed and overwritten, do not
|
|
||||||
* return an instance that is useful elsewhere. In particular, do not return a common instance,
|
|
||||||
* always use {@code new} to create a new instance.
|
|
||||||
*
|
|
||||||
* @param type the parameterized T represented as a {@link Type}.
|
|
||||||
* @return a default object instance of type T.
|
|
||||||
*/
|
|
||||||
public T createInstance(Type type);
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>The following is an example:</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* class IntWrapper {
|
|
||||||
* public int integerField = 0;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* JavaFieldNamingPolicy policy = new JavaFieldNamingPolicy();
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
|
||||||
*
|
|
||||||
* assert("integerField".equals(translatedFieldName));
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>This is the default {@link FieldNamingStrategy2} used by Gson.</p>
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class JavaFieldNamingPolicy extends RecursiveFieldNamingPolicy {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<JsonElement> {
|
|
||||||
private final List<JsonElement> elements;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty JsonArray.
|
|
||||||
*/
|
|
||||||
public JsonArray() {
|
|
||||||
elements = new ArrayList<JsonElement>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the specified element to self.
|
|
||||||
*
|
|
||||||
* @param element the element that needs to be added to the array.
|
|
||||||
*/
|
|
||||||
public void add(JsonElement element) {
|
|
||||||
if (element == null) {
|
|
||||||
element = JsonNull.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<JsonElement> iterator() {
|
|
||||||
return elements.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the ith element of the array.
|
|
||||||
*
|
|
||||||
* @param i the index of the element that is being sought.
|
|
||||||
* @return the element present at the ith index.
|
|
||||||
* @throws IndexOutOfBoundsException if i is negative or greater than or equal to the
|
|
||||||
* {@link #size()} of the array.
|
|
||||||
*/
|
|
||||||
public JsonElement get(int i) {
|
|
||||||
return elements.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a {@link Number} if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a number if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid Number.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Number getAsNumber() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsNumber();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a {@link String} if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a String if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid String.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getAsString() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsString();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a double if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a double if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid double.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public double getAsDouble() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsDouble();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a {@link BigDecimal} if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a {@link BigDecimal} if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
|
|
||||||
* @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public BigDecimal getAsBigDecimal() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsBigDecimal();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a {@link BigInteger} if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a {@link BigInteger} if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive}.
|
|
||||||
* @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public BigInteger getAsBigInteger() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsBigInteger();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a float if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a float if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid float.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public float getAsFloat() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsFloat();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a long if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a long if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid long.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public long getAsLong() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsLong();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as an integer if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as an integer if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid integer.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getAsInt() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsInt();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte getAsByte() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsByte();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public char getAsCharacter() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsCharacter();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a primitive short if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a primitive short if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid short.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public short getAsShort() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsShort();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this array as a boolean if it contains a single element.
|
|
||||||
*
|
|
||||||
* @return get this element as a boolean if it is single element array.
|
|
||||||
* @throws ClassCastException if the element in the array is of not a {@link JsonPrimitive} and
|
|
||||||
* is not a valid boolean.
|
|
||||||
* @throws IllegalStateException if the array has more than one element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean getAsBoolean() {
|
|
||||||
if (elements.size() == 1) {
|
|
||||||
return elements.get(0).getAsBoolean();
|
|
||||||
}
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(']');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<T> extends JsonDeserializationVisitor<T> {
|
|
||||||
|
|
||||||
JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType,
|
|
||||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
|
||||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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 <T> The type of the deserialized object.
|
|
||||||
* @return An object of type typeOfT.
|
|
||||||
* @throws JsonParseException if the parse tree does not contain expected data.
|
|
||||||
*/
|
|
||||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<JsonDeserializer<?>> deserializers;
|
|
||||||
private final MappedObjectConstructor objectConstructor;
|
|
||||||
|
|
||||||
JsonDeserializationContextDefault(ObjectNavigatorFactory navigatorFactory,
|
|
||||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
|
||||||
MappedObjectConstructor objectConstructor) {
|
|
||||||
this.navigatorFactory = navigatorFactory;
|
|
||||||
this.deserializers = deserializers;
|
|
||||||
this.objectConstructor = objectConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectConstructor getObjectConstructor() {
|
|
||||||
return objectConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> 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> T fromJsonArray(Type arrayType, JsonArray jsonArray,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
JsonArrayDeserializationVisitor<T> visitor = new JsonArrayDeserializationVisitor<T>(
|
|
||||||
jsonArray, arrayType, navigatorFactory, objectConstructor, deserializers, context);
|
|
||||||
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, arrayType, true));
|
|
||||||
on.accept(visitor);
|
|
||||||
return visitor.getTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T fromJsonObject(Type typeOfT, JsonObject jsonObject,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
|
||||||
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> T fromJsonPrimitive(Type typeOfT, JsonPrimitive json,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<T> implements ObjectNavigator.Visitor {
|
|
||||||
|
|
||||||
protected final ObjectNavigatorFactory factory;
|
|
||||||
protected final ObjectConstructor objectConstructor;
|
|
||||||
protected final ParameterizedTypeHandlerMap<JsonDeserializer<?>> 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<JsonDeserializer<?>> 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<JsonDeserializer<?>, 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<JsonDeserializer<?>, 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<Object>(jsonChild, childType,
|
|
||||||
factory, objectConstructor, deserializers, context);
|
|
||||||
return visitChild(childType, childVisitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Object visitChildAsArray(Type childType, JsonArray jsonChild) {
|
|
||||||
JsonDeserializationVisitor<?> childVisitor =
|
|
||||||
new JsonArrayDeserializationVisitor<Object>(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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Interface representing a custom deserializer for Json. You should write a custom
|
|
||||||
* deserializer, if you are not happy with the default deserialization done by Gson. You will
|
|
||||||
* also need to register this deserializer through
|
|
||||||
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}.</p>
|
|
||||||
*
|
|
||||||
* <p>Let us look at example where defining a deserializer will be useful. The {@code Id} class
|
|
||||||
* defined below has two fields: {@code clazz} and {@code value}.</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* public class Id<T> {
|
|
||||||
* private final Class<T> clazz;
|
|
||||||
* private final long value;
|
|
||||||
* public Id(Class<T> clazz, long value) {
|
|
||||||
* this.clazz = clazz;
|
|
||||||
* this.value = value;
|
|
||||||
* }
|
|
||||||
* public long getValue() {
|
|
||||||
* return value;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>The default deserialization of {@code Id(com.foo.MyObject.class, 20L)} will require the
|
|
||||||
* Json string to be <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you already know
|
|
||||||
* the type of the field that the {@code Id} will be deserialized into, and hence just want to
|
|
||||||
* deserialize it from a Json string {@code 20}. You can achieve that by writing a custom
|
|
||||||
* deserializer:</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* class IdDeserializer implements JsonDeserializer<Id>() {
|
|
||||||
* public Id fromJson(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
* throws JsonParseException {
|
|
||||||
* return (Id) new Id((Class)typeOfT, id.getValue());
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>You will also need to register {@code IdDeserializer} with Gson as follows:</p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdDeserializer()).create();
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*
|
|
||||||
* @param <T> type for which the deserializer is being registered. It is possible that a
|
|
||||||
* deserializer may be asked to deserialize a specific generic type of the T.
|
|
||||||
*/
|
|
||||||
public interface JsonDeserializer<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gson invokes this call-back method during deserialization when it encounters a field of the
|
|
||||||
* specified type.
|
|
||||||
* <p>In the implementation of this call-back method, you should consider invoking
|
|
||||||
* {@link JsonDeserializationContext#deserialize(JsonElement, Type)} method to create objects
|
|
||||||
* for any non-trivial field of the returned object. However, you should never invoke it on the
|
|
||||||
* the same type passing {@code json} since that will cause an infinite loop (Gson will call your
|
|
||||||
* call-back method again).
|
|
||||||
*
|
|
||||||
* @param json The Json data being deserialized
|
|
||||||
* @param typeOfT The type of the Object to deserialize to
|
|
||||||
* @return a deserialized object of the specified type typeOfT which is a subclass of {@code T}
|
|
||||||
* @throws JsonParseException if json is not in the expected format of {@code typeofT}
|
|
||||||
*/
|
|
||||||
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException;
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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 <T> type of the deserializer being wrapped.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
|
|
||||||
|
|
||||||
private final JsonDeserializer<T> delegate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a wrapped {@link JsonDeserializer} object that has been decorated with
|
|
||||||
* {@link JsonParseException} handling.
|
|
||||||
*
|
|
||||||
* @param delegate the {@code JsonDeserializer} instance to be wrapped.
|
|
||||||
* @throws IllegalArgumentException if {@code delegate} is {@code null}.
|
|
||||||
*/
|
|
||||||
JsonDeserializerExceptionWrapper(JsonDeserializer<T> delegate) {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,338 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>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.</p>
|
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<String, JsonElement> members;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty JsonObject.
|
|
||||||
*/
|
|
||||||
public JsonObject() {
|
|
||||||
members = new LinkedHashMap<String, JsonElement>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<Map.Entry<String, JsonElement>> entrySet() {
|
|
||||||
return members.entrySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method to check if a member with the specified name is present in this object.
|
|
||||||
*
|
|
||||||
* @param memberName name of the member that is being checked for presence.
|
|
||||||
* @return true if there is a member with the specified name, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean has(String memberName) {
|
|
||||||
return members.containsKey(memberName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the member with the specified name.
|
|
||||||
*
|
|
||||||
* @param memberName name of the member that is being requested.
|
|
||||||
* @return the member matching the name. Null if no such member exists.
|
|
||||||
*/
|
|
||||||
public JsonElement get(String memberName) {
|
|
||||||
if (members.containsKey(memberName)) {
|
|
||||||
JsonElement member = members.get(memberName);
|
|
||||||
return member == null ? JsonNull.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<String, JsonElement> 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('}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<T> extends JsonDeserializationVisitor<T> {
|
|
||||||
|
|
||||||
JsonObjectDeserializationVisitor(JsonElement json, Type type,
|
|
||||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
|
||||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> 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<JsonDeserializer<?>, 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>This exception is a {@link RuntimeException} because it is exposed to the client. Using a
|
|
||||||
* {@link RuntimeException} avoids bad coding practices on the client side where they catch the
|
|
||||||
* exception and do nothing. It is often the case that you want to blow up if there is a parsing
|
|
||||||
* error (i.e. often clients do not know how to recover from a {@link JsonParseException}.</p>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
public class JsonParseException extends RuntimeException {
|
|
||||||
static final long serialVersionUID = -4086729973971783390L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates exception with the specified message. If you are wrapping another exception, consider
|
|
||||||
* using {@link #JsonParseException(String, Throwable)} instead.
|
|
||||||
*
|
|
||||||
* @param msg error message describing a possible cause of this exception.
|
|
||||||
*/
|
|
||||||
public JsonParseException(String msg) {
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates exception with the specified message and cause.
|
|
||||||
*
|
|
||||||
* @param msg error message describing what happened.
|
|
||||||
* @param cause root exception that caused this exception to be thrown.
|
|
||||||
*/
|
|
||||||
public JsonParseException(String msg, Throwable cause) {
|
|
||||||
super(msg, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates exception with the specified cause. Consider using
|
|
||||||
* {@link #JsonParseException(String, Throwable)} instead if you can describe what happened.
|
|
||||||
*
|
|
||||||
* @param cause root exception that caused this exception to be thrown.
|
|
||||||
*/
|
|
||||||
public JsonParseException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,387 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<JsonSerializer<?>> serializers;
|
|
||||||
private final boolean serializeNulls;
|
|
||||||
private final MemoryRefStack ancestors;
|
|
||||||
|
|
||||||
JsonSerializationContextDefault(ObjectNavigatorFactory factory, boolean serializeNulls,
|
|
||||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<JsonSerializer<?>> serializers;
|
|
||||||
private final boolean serializeNulls;
|
|
||||||
private final JsonSerializationContext context;
|
|
||||||
private final MemoryRefStack ancestors;
|
|
||||||
private JsonElement root;
|
|
||||||
|
|
||||||
JsonSerializationVisitor(ObjectNavigatorFactory factory, boolean serializeNulls,
|
|
||||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> 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<JsonSerializer<?>,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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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)}.
|
|
||||||
*
|
|
||||||
* <p>Let us look at example where defining a serializer will be useful. The {@code Id} class
|
|
||||||
* defined below has two fields: {@code clazz} and {@code value}.</p>
|
|
||||||
*
|
|
||||||
* <p><pre>
|
|
||||||
* public class Id<T> {
|
|
||||||
* private final Class<T> clazz;
|
|
||||||
* private final long value;
|
|
||||||
*
|
|
||||||
* public Id(Class<T> clazz, long value) {
|
|
||||||
* this.clazz = clazz;
|
|
||||||
* this.value = value;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public long getValue() {
|
|
||||||
* return value;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* <p>The default serialization of {@code Id(com.foo.MyObject.class, 20L)} will be
|
|
||||||
* <code>{"clazz":com.foo.MyObject,"value":20}</code>. Suppose, you just want the output to be
|
|
||||||
* the value instead, which is {@code 20} in this case. You can achieve that by writing a custom
|
|
||||||
* serializer:</p>
|
|
||||||
*
|
|
||||||
* <p><pre>
|
|
||||||
* class IdSerializer implements JsonSerializer<Id>() {
|
|
||||||
* public JsonElement toJson(Id id, Type typeOfId, JsonSerializationContext context) {
|
|
||||||
* return new JsonPrimitive(id.getValue());
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* <p>You will also need to register {@code IdSerializer} with Gson as follows:</p>
|
|
||||||
* <pre>
|
|
||||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdSerializer()).create();
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*
|
|
||||||
* @param <T> type for which the serializer is being registered. It is possible that a serializer
|
|
||||||
* may be asked to serialize a specific generic type of the T.
|
|
||||||
*/
|
|
||||||
public interface JsonSerializer<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gson invokes this call-back method during serialization when it encounters a field of the
|
|
||||||
* specified type.
|
|
||||||
*
|
|
||||||
* <p>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).</p>
|
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>This class is conditionally thread-safe (see Item 70, Effective Java second edition). To
|
|
||||||
* properly use this class across multiple threads, you will need to add some external
|
|
||||||
* synchronization. For example:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* 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();
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
* @since 1.4
|
|
||||||
*/
|
|
||||||
public final class JsonStreamParser implements Iterator<JsonElement> {
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<String, JsonElement> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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}.
|
|
||||||
*
|
|
||||||
*<p>The following is an example:</p>
|
|
||||||
* <pre>
|
|
||||||
* class StringWrapper {
|
|
||||||
* public String AStringField = "abcd";
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* LowerCamelCaseSeparatorNamingPolicy policy = new LowerCamelCaseSeparatorNamingPolicy("_");
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(StringWrapper.class.getField("AStringField"));
|
|
||||||
*
|
|
||||||
* assert("a_string_field".equals(translatedFieldName));
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class LowerCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
|
|
||||||
|
|
||||||
public LowerCamelCaseSeparatorNamingPolicy(String separatorString) {
|
|
||||||
super(new CamelCaseSeparatorNamingPolicy(separatorString), new LowerCaseNamingPolicy());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>The following is an example:</p>
|
|
||||||
* <pre>
|
|
||||||
* class IntWrapper {
|
|
||||||
* public int integerField = 0;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* LowerCaseNamingPolicy policy = new LowerCaseNamingPolicy();
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
|
||||||
*
|
|
||||||
* assert("integerfield".equals(translatedFieldName));
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class LowerCaseNamingPolicy extends RecursiveFieldNamingPolicy {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String translateName(String target, Type fieldType,
|
|
||||||
Collection<Annotation> annotations) {
|
|
||||||
return target.toLowerCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<K, V> extends LinkedHashMap<K, V> implements Cache<K, V> {
|
|
||||||
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<K, V> entry) {
|
|
||||||
return size() > maxCapacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <h3>Maps as JSON objects</h3>
|
|
||||||
* 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: <pre> {@code
|
|
||||||
* Map<Point, String> original = new LinkedHashMap<Point, String>();
|
|
||||||
* original.put(new Point(5, 6), "a");
|
|
||||||
* original.put(new Point(8, 8), "b");
|
|
||||||
* System.out.println(gson.toJson(original, type));
|
|
||||||
* }</pre>
|
|
||||||
* The above code prints this JSON object:<pre> {@code
|
|
||||||
* {
|
|
||||||
* "(5,6)": "a",
|
|
||||||
* "(8,8)": "b"
|
|
||||||
* }
|
|
||||||
* }</pre>
|
|
||||||
* But GSON is unable to deserialize this value because the JSON string name is
|
|
||||||
* just the {@link Object#toString() toString()} of the map key. Attempting to
|
|
||||||
* convert the above JSON to an object fails with a parse exception:
|
|
||||||
* <pre>com.bukkit.mcteam.gson.JsonParseException: Expecting object found: "(5,6)"
|
|
||||||
* at com.bukkit.mcteam.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
|
|
||||||
* at com.bukkit.mcteam.gson.ObjectNavigator.navigateClassFields
|
|
||||||
* ...</pre>
|
|
||||||
*
|
|
||||||
* <h3>Maps as JSON arrays</h3>
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>Register this adapter when you are creating your GSON instance.
|
|
||||||
* <pre> {@code
|
|
||||||
* Gson gson = new GsonBuilder()
|
|
||||||
* .registerTypeAdapter(Map.class, new MapAsArrayTypeAdapter())
|
|
||||||
* .create();
|
|
||||||
* }</pre>
|
|
||||||
* 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:
|
|
||||||
* <pre> {@code
|
|
||||||
* [
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* "x": 5,
|
|
||||||
* "y": 6
|
|
||||||
* },
|
|
||||||
* "a",
|
|
||||||
* ],
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* "x": 8,
|
|
||||||
* "y": 8
|
|
||||||
* },
|
|
||||||
* "b"
|
|
||||||
* ]
|
|
||||||
* ]
|
|
||||||
* }</pre>
|
|
||||||
* This format will serialize and deserialize just fine as long as this adapter
|
|
||||||
* is registered.
|
|
||||||
*
|
|
||||||
* <p>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<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
|
||||||
|
|
||||||
public Map<?, ?> deserialize(JsonElement json, Type typeOfT,
|
|
||||||
JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
Map<Object, Object> result = new LinkedHashMap<Object, Object>();
|
|
||||||
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<String, JsonElement> 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<JsonElement> keysAndValues = new ArrayList<JsonElement>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<InstanceCreator<?>> instanceCreatorMap;
|
|
||||||
|
|
||||||
public MappedObjectConstructor(
|
|
||||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) {
|
|
||||||
instanceCreatorMap = instanceCreators;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T construct(Type typeOfT) {
|
|
||||||
InstanceCreator<T> creator = (InstanceCreator<T>) 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> T constructWithNoArgConstructor(Type typeOfT) {
|
|
||||||
try {
|
|
||||||
Constructor<T> 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 <T> Constructor<T> getNoArgsConstructor(Type typeOfT) {
|
|
||||||
TypeInfo typeInfo = new TypeInfo(typeOfT);
|
|
||||||
Class<T> clazz = (Class<T>) typeInfo.getRawClass();
|
|
||||||
Constructor<T>[] declaredConstructors = (Constructor<T>[]) clazz.getDeclaredConstructors();
|
|
||||||
AccessibleObject.setAccessible(declaredConstructors, true);
|
|
||||||
for (Constructor<T> constructor : declaredConstructors) {
|
|
||||||
if (constructor.getParameterTypes().length == 0) {
|
|
||||||
return constructor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use this methods to register an {@link InstanceCreator} for a new type.
|
|
||||||
*
|
|
||||||
* @param <T> 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
|
|
||||||
*/
|
|
||||||
<T> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<ObjectTypePair> stack = new Stack<ObjectTypePair>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<Integer> modifiers;
|
|
||||||
|
|
||||||
public ModifierBasedExclusionStrategy(int... modifiers) {
|
|
||||||
this.modifiers = new HashSet<Integer>();
|
|
||||||
if (modifiers != null) {
|
|
||||||
for (int modifier : modifiers) {
|
|
||||||
this.modifiers.add(modifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldSkipField(FieldAttributes f) {
|
|
||||||
for (int modifier : modifiers) {
|
|
||||||
if (f.hasModifier(modifier)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldSkipClass(Class<?> clazz) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
*<p>The following is an example:</p>
|
|
||||||
* <pre>
|
|
||||||
* class StringWrapper {
|
|
||||||
* public String stringField = "abcd";
|
|
||||||
* public String _stringField = "efg";
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* ModifyFirstLetterNamingPolicy policy =
|
|
||||||
* new ModifyFirstLetterNamingPolicy(LetterModifier.UPPER);
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(StringWrapper.class.getField("stringField"));
|
|
||||||
*
|
|
||||||
* assert("StringField".equals(translatedFieldName));
|
|
||||||
*
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(StringWrapper.class.getField("_stringField"));
|
|
||||||
*
|
|
||||||
* assert("_StringField".equals(translatedFieldName));
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
|
|
||||||
|
|
||||||
public enum LetterModifier {
|
|
||||||
UPPER,
|
|
||||||
LOWER;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final LetterModifier letterModifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new ModifyFirstLetterNamingPolicy that will either modify the first letter of the
|
|
||||||
* target name to either UPPER case or LOWER case depending on the {@code modifier} parameter.
|
|
||||||
*
|
|
||||||
* @param modifier the type of modification that should be performed
|
|
||||||
* @throws IllegalArgumentException if {@code modifier} is null
|
|
||||||
*/
|
|
||||||
public ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
|
|
||||||
Preconditions.checkNotNull(modifier);
|
|
||||||
this.letterModifier = modifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String translateName(String target, Type fieldType,
|
|
||||||
Collection<Annotation> annotations) {
|
|
||||||
StringBuilder fieldNameBuilder = new StringBuilder();
|
|
||||||
int index = 0;
|
|
||||||
char firstCharacter = target.charAt(index);
|
|
||||||
|
|
||||||
while (index < target.length() - 1) {
|
|
||||||
if (Character.isLetter(firstCharacter)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldNameBuilder.append(firstCharacter);
|
|
||||||
firstCharacter = target.charAt(++index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == target.length()) {
|
|
||||||
return fieldNameBuilder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean capitalizeFirstLetter = (letterModifier == LetterModifier.UPPER);
|
|
||||||
if (capitalizeFirstLetter && !Character.isUpperCase(firstCharacter)) {
|
|
||||||
String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), target, ++index);
|
|
||||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
|
||||||
} else if (!capitalizeFirstLetter && Character.isUpperCase(firstCharacter)) {
|
|
||||||
String modifiedTarget = modifyString(Character.toLowerCase(firstCharacter), target, ++index);
|
|
||||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
|
||||||
} else {
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
|
|
||||||
return indexOfSubstring < srcString.length() ?
|
|
||||||
firstCharacter + srcString.substring(indexOfSubstring)
|
|
||||||
: String.valueOf(firstCharacter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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> 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);
|
|
||||||
}
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
<HANDLER> Pair<HANDLER, ObjectTypePair> getMatchingHandler(
|
|
||||||
ParameterizedTypeHandlerMap<HANDLER> 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, ObjectTypePair>(handler, moreSpecificType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Try the specified type
|
|
||||||
handler = handlers.getHandlerFor(type);
|
|
||||||
return handler == null ? null : new Pair<HANDLER, ObjectTypePair>(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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 <FIRST>
|
|
||||||
* @param <SECOND>
|
|
||||||
*/
|
|
||||||
final class Pair<FIRST, SECOND> {
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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 <T> The handler that will be looked up by type
|
|
||||||
*/
|
|
||||||
final class ParameterizedTypeHandlerMap<T> {
|
|
||||||
private static final Logger logger =
|
|
||||||
Logger.getLogger(ParameterizedTypeHandlerMap.class.getName());
|
|
||||||
private final Map<Type, T> map = new HashMap<Type, T>();
|
|
||||||
private final List<Pair<Class<?>, T>> typeHierarchyList = new ArrayList<Pair<Class<?>, T>>();
|
|
||||||
private boolean modifiable = true;
|
|
||||||
|
|
||||||
public synchronized void registerForTypeHierarchy(Class<?> typeOfT, T value) {
|
|
||||||
Pair<Class<?>, T> pair = new Pair<Class<?>, T>(typeOfT, value);
|
|
||||||
registerForTypeHierarchy(pair);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void registerForTypeHierarchy(Pair<Class<?>, 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<Class<?>, 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<T> other) {
|
|
||||||
if (!modifiable) {
|
|
||||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
|
||||||
}
|
|
||||||
for (Map.Entry<Type, T> 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<Class<?>, 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<Class<?>, 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<T> copyOf() {
|
|
||||||
ParameterizedTypeHandlerMap<T> copy = new ParameterizedTypeHandlerMap<T>();
|
|
||||||
for (Map.Entry<Type, T> entry : map.entrySet()) {
|
|
||||||
copy.register(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
for (Pair<Class<?>, T> entry : typeHierarchyList) {
|
|
||||||
copy.registerForTypeHierarchy(entry);
|
|
||||||
}
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder("{mapForTypeHierarchy:{");
|
|
||||||
boolean first = true;
|
|
||||||
for (Pair<Class<?>, 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<Type, T> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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}.
|
|
||||||
*
|
|
||||||
* <p>Here's an example class:
|
|
||||||
* <pre>
|
|
||||||
* class Foo<T> {
|
|
||||||
* private List<T> someList;
|
|
||||||
*
|
|
||||||
* Foo(List<T> list) {
|
|
||||||
* this.someList = list;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple utility class used to check method Preconditions.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* public long divideBy(long value) {
|
|
||||||
* Preconditions.checkArgument(value != 0);
|
|
||||||
* return this.value / value;
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class Preconditions {
|
|
||||||
public static void checkNotNull(Object obj) {
|
|
||||||
checkArgument(obj != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkArgument(boolean condition) {
|
|
||||||
if (!condition) {
|
|
||||||
throw new IllegalArgumentException("condition failed: " + condition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkState(boolean condition) {
|
|
||||||
if (!condition) {
|
|
||||||
throw new IllegalArgumentException("condition failed: " + condition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains static utility methods pertaining to primitive types and their
|
|
||||||
* corresponding wrapper types.
|
|
||||||
*
|
|
||||||
* @author Kevin Bourrillion
|
|
||||||
*/
|
|
||||||
final class Primitives {
|
|
||||||
private Primitives() {}
|
|
||||||
|
|
||||||
/** A map from primitive types to their corresponding wrapper types. */
|
|
||||||
public static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE;
|
|
||||||
|
|
||||||
/** A map from wrapper types to their corresponding primitive types. */
|
|
||||||
public static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE;
|
|
||||||
|
|
||||||
// Sad that we can't use a BiMap. :(
|
|
||||||
|
|
||||||
static {
|
|
||||||
Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16);
|
|
||||||
Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16);
|
|
||||||
|
|
||||||
add(primToWrap, wrapToPrim, boolean.class, Boolean.class);
|
|
||||||
add(primToWrap, wrapToPrim, byte.class, Byte.class);
|
|
||||||
add(primToWrap, wrapToPrim, char.class, Character.class);
|
|
||||||
add(primToWrap, wrapToPrim, double.class, Double.class);
|
|
||||||
add(primToWrap, wrapToPrim, float.class, Float.class);
|
|
||||||
add(primToWrap, wrapToPrim, int.class, Integer.class);
|
|
||||||
add(primToWrap, wrapToPrim, long.class, Long.class);
|
|
||||||
add(primToWrap, wrapToPrim, short.class, Short.class);
|
|
||||||
add(primToWrap, wrapToPrim, void.class, Void.class);
|
|
||||||
|
|
||||||
PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap);
|
|
||||||
WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void add(Map<Class<?>, Class<?>> forward,
|
|
||||||
Map<Class<?>, Class<?>> backward, Class<?> key, Class<?> value) {
|
|
||||||
forward.put(key, value);
|
|
||||||
backward.put(value, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns {@code true} if {@code type} is one of the nine
|
|
||||||
* primitive-wrapper types, such as {@link Integer}.
|
|
||||||
*
|
|
||||||
* @see Class#isPrimitive
|
|
||||||
*/
|
|
||||||
public static boolean isWrapperType(Class<?> type) {
|
|
||||||
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(checkNotNull(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Class<?> checkNotNull(Class<?> type) {
|
|
||||||
Preconditions.checkNotNull(type);
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the corresponding wrapper type of {@code type} if it is a primitive
|
|
||||||
* type; otherwise returns {@code type} itself. Idempotent.
|
|
||||||
* <pre>
|
|
||||||
* wrap(int.class) == Integer.class
|
|
||||||
* wrap(Integer.class) == Integer.class
|
|
||||||
* wrap(String.class) == String.class
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public static <T> Class<T> wrap(Class<T> type) {
|
|
||||||
checkNotNull(type);
|
|
||||||
|
|
||||||
// cast is safe: long.class and Long.class are both of type Class<Long>
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<T> wrapped = (Class<T>) 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.
|
|
||||||
* <pre>
|
|
||||||
* unwrap(Integer.class) == int.class
|
|
||||||
* unwrap(int.class) == int.class
|
|
||||||
* unwrap(String.class) == String.class
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public static <T> Class<T> unwrap(Class<T> type) {
|
|
||||||
checkNotNull(type);
|
|
||||||
|
|
||||||
// cast is safe: long.class and Long.class are both of type Class<Long>
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get(type);
|
|
||||||
return (unwrapped == null) ? type : unwrapped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<Annotation> annotations);
|
|
||||||
}
|
|
||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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}.
|
|
||||||
*
|
|
||||||
* <p>NOTE: this class performs JSON field name validation for any of the fields marked with
|
|
||||||
* an {@code @SerializedName} annotation.</p>
|
|
||||||
*
|
|
||||||
* @see SerializedName
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 {
|
|
||||||
private 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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<String, JsonElement> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A data object that stores attributes of a field.
|
|
||||||
*
|
|
||||||
* <p>This class is immutable; therefore, it can be safely shared across threads.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*
|
|
||||||
* @since 1.4
|
|
||||||
*/
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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> T adaptType(Object from, Class<T> to);
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
* <pre>
|
|
||||||
* wrap(int.class) == Integer.class
|
|
||||||
* wrap(Integer.class) == Integer.class
|
|
||||||
* wrap(String.class) == String.class
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public final Class<?> getWrappedClass() {
|
|
||||||
return Primitives.wrap(rawClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the raw class associated with this type
|
|
||||||
*/
|
|
||||||
public final Class<?> getRawClass() {
|
|
||||||
return rawClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isCollectionOrArray() {
|
|
||||||
return Collection.class.isAssignableFrom(rawClass) || isArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isArray() {
|
|
||||||
return TypeUtils.isArray(rawClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isEnum() {
|
|
||||||
return rawClass.isEnum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isPrimitive() {
|
|
||||||
return Primitives.isWrapperType(Primitives.wrap(rawClass));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.GenericArrayType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to extract information about types used to define a generic array.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class TypeInfoArray extends TypeInfo {
|
|
||||||
private final Class<?> componentRawType;
|
|
||||||
private final Type secondLevel;
|
|
||||||
|
|
||||||
TypeInfoArray(Type type) {
|
|
||||||
super(type);
|
|
||||||
Class<?> rootComponentType = rawClass;
|
|
||||||
while (rootComponentType.isArray()) {
|
|
||||||
rootComponentType = rootComponentType.getComponentType();
|
|
||||||
}
|
|
||||||
this.componentRawType = rootComponentType;
|
|
||||||
this.secondLevel = extractSecondLevelType(actualType, rawClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type extractSecondLevelType(Type actualType, Class<?> rawClass) {
|
|
||||||
return actualType instanceof GenericArrayType ?
|
|
||||||
((GenericArrayType) actualType).getGenericComponentType() : rawClass.getComponentType();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the raw type unwrapped of the second level of array.
|
|
||||||
* If the object is (single-dimensional or multi-dimensional) array, it is the class of the
|
|
||||||
* elements of the array. For example, this method returns Foo.class for Foo[].
|
|
||||||
* It will return Foo[].class for Foo[][]. For Foo<String>[][] types, it will return the
|
|
||||||
* type representing Foo<String>[]
|
|
||||||
* (i.e. <code>new TypeToken<Foo<String>[]>() {}.getType()</code>).
|
|
||||||
*/
|
|
||||||
public Type getSecondLevelType() {
|
|
||||||
return secondLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the raw type of the root component.
|
|
||||||
* If the object is a single-dimensional array then the component type is the class of an
|
|
||||||
* element of the array.
|
|
||||||
* If the object is a multi-dimensional array then the component type is the class of the
|
|
||||||
* inner-most array element. For example, the This method will return Foo.class for Foo[][][].
|
|
||||||
*/
|
|
||||||
public Class<?> getComponentRawType() {
|
|
||||||
return componentRawType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A convenience object for retrieving the map type information.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class TypeInfoCollection {
|
|
||||||
private final ParameterizedType collectionType;
|
|
||||||
|
|
||||||
public TypeInfoCollection(Type collectionType) {
|
|
||||||
if (!(collectionType instanceof ParameterizedType)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Collection objects need to be parameterized unless you use a custom serializer. "
|
|
||||||
+ "Use the com.bukkit.mcteam.gson.reflect.TypeToken to extract the ParameterizedType.");
|
|
||||||
}
|
|
||||||
TypeInfo rawType = new TypeInfo(collectionType);
|
|
||||||
Preconditions.checkArgument(Collection.class.isAssignableFrom(rawType.getRawClass()));
|
|
||||||
this.collectionType = (ParameterizedType) collectionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getElementType() {
|
|
||||||
return collectionType.getActualTypeArguments()[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.GenericArrayType;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.lang.reflect.TypeVariable;
|
|
||||||
import java.lang.reflect.WildcardType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A static factory class used to construct the "TypeInfo" objects.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class TypeInfoFactory {
|
|
||||||
|
|
||||||
private TypeInfoFactory() {
|
|
||||||
// Not instantiable since it provides factory methods only.
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TypeInfoArray getTypeInfoForArray(Type type) {
|
|
||||||
Preconditions.checkArgument(TypeUtils.isArray(type));
|
|
||||||
return new TypeInfoArray(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluates the "actual" type for the field. If the field is a "TypeVariable" or has a
|
|
||||||
* "TypeVariable" in a parameterized type then it evaluates the real type.
|
|
||||||
*
|
|
||||||
* @param f the actual field object to retrieve the type from
|
|
||||||
* @param typeDefiningF the type that contains the field {@code f}
|
|
||||||
* @return the type information for the field
|
|
||||||
*/
|
|
||||||
public static TypeInfo getTypeInfoForField(Field f, Type typeDefiningF) {
|
|
||||||
Class<?> classDefiningF = TypeUtils.toRawClass(typeDefiningF);
|
|
||||||
Type type = f.getGenericType();
|
|
||||||
Type actualType = getActualType(type, typeDefiningF, classDefiningF);
|
|
||||||
return new TypeInfo(actualType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type getActualType(
|
|
||||||
Type typeToEvaluate, Type parentType, Class<?> rawParentClass) {
|
|
||||||
if (typeToEvaluate instanceof Class<?>) {
|
|
||||||
return typeToEvaluate;
|
|
||||||
} else if (typeToEvaluate instanceof ParameterizedType) {
|
|
||||||
ParameterizedType castedType = (ParameterizedType) typeToEvaluate;
|
|
||||||
Type owner = castedType.getOwnerType();
|
|
||||||
Type[] actualTypeParameters =
|
|
||||||
extractRealTypes(castedType.getActualTypeArguments(), parentType, rawParentClass);
|
|
||||||
Type rawType = castedType.getRawType();
|
|
||||||
return new ParameterizedTypeImpl(rawType, actualTypeParameters, owner);
|
|
||||||
} else if (typeToEvaluate instanceof GenericArrayType) {
|
|
||||||
GenericArrayType castedType = (GenericArrayType) typeToEvaluate;
|
|
||||||
Type componentType = castedType.getGenericComponentType();
|
|
||||||
Type actualType = getActualType(componentType, parentType, rawParentClass);
|
|
||||||
if (componentType.equals(actualType)) {
|
|
||||||
return castedType;
|
|
||||||
}
|
|
||||||
return actualType instanceof Class<?> ?
|
|
||||||
TypeUtils.wrapWithArray(TypeUtils.toRawClass(actualType))
|
|
||||||
: new GenericArrayTypeImpl(actualType);
|
|
||||||
} else if (typeToEvaluate instanceof TypeVariable<?>) {
|
|
||||||
if (parentType instanceof ParameterizedType) {
|
|
||||||
// The class definition has the actual types used for the type variables.
|
|
||||||
// Find the matching actual type for the Type Variable used for the field.
|
|
||||||
// For example, class Foo<A> { A a; }
|
|
||||||
// new Foo<Integer>(); defines the actual type of A to be Integer.
|
|
||||||
// So, to find the type of the field a, we will have to look at the class'
|
|
||||||
// actual type arguments.
|
|
||||||
TypeVariable<?> fieldTypeVariable = (TypeVariable<?>) typeToEvaluate;
|
|
||||||
TypeVariable<?>[] classTypeVariables = rawParentClass.getTypeParameters();
|
|
||||||
ParameterizedType objParameterizedType = (ParameterizedType) parentType;
|
|
||||||
int indexOfActualTypeArgument = getIndex(classTypeVariables, fieldTypeVariable);
|
|
||||||
Type[] actualTypeArguments = objParameterizedType.getActualTypeArguments();
|
|
||||||
return actualTypeArguments[indexOfActualTypeArgument];
|
|
||||||
} else if (typeToEvaluate instanceof TypeVariable<?>) {
|
|
||||||
Type theSearchedType = null;
|
|
||||||
|
|
||||||
do {
|
|
||||||
theSearchedType = extractTypeForHierarchy(parentType, (TypeVariable<?>) typeToEvaluate);
|
|
||||||
} while ((theSearchedType != null) && (theSearchedType instanceof TypeVariable<?>));
|
|
||||||
|
|
||||||
if (theSearchedType != null) {
|
|
||||||
return theSearchedType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UnsupportedOperationException("Expecting parameterized type, got " + parentType
|
|
||||||
+ ".\n Are you missing the use of TypeToken idiom?\n See "
|
|
||||||
+ "http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener");
|
|
||||||
} else if (typeToEvaluate instanceof WildcardType) {
|
|
||||||
WildcardType castedType = (WildcardType) typeToEvaluate;
|
|
||||||
return getActualType(castedType.getUpperBounds()[0], parentType, rawParentClass);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("Type \'" + typeToEvaluate + "\' is not a Class, "
|
|
||||||
+ "ParameterizedType, GenericArrayType or TypeVariable. Can't extract type.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type extractTypeForHierarchy(Type parentType, TypeVariable<?> typeToEvaluate) {
|
|
||||||
Class<?> rawParentType = null;
|
|
||||||
if (parentType instanceof Class<?>) {
|
|
||||||
rawParentType = (Class<?>) parentType;
|
|
||||||
} else if (parentType instanceof ParameterizedType) {
|
|
||||||
ParameterizedType parentTypeAsPT = (ParameterizedType) parentType;
|
|
||||||
rawParentType = (Class<?>) parentTypeAsPT.getRawType();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type superClass = rawParentType.getGenericSuperclass();
|
|
||||||
if (superClass instanceof ParameterizedType
|
|
||||||
&& ((ParameterizedType) superClass).getRawType() == typeToEvaluate.getGenericDeclaration()) {
|
|
||||||
// Evaluate type on this type
|
|
||||||
TypeVariable<?>[] classTypeVariables =
|
|
||||||
((Class<?>) ((ParameterizedType) superClass).getRawType()).getTypeParameters();
|
|
||||||
int indexOfActualTypeArgument = getIndex(classTypeVariables, typeToEvaluate);
|
|
||||||
|
|
||||||
Type[] actualTypeArguments = null;
|
|
||||||
if (parentType instanceof Class<?>) {
|
|
||||||
actualTypeArguments = ((ParameterizedType) superClass).getActualTypeArguments();
|
|
||||||
} else if (parentType instanceof ParameterizedType) {
|
|
||||||
actualTypeArguments = ((ParameterizedType) parentType).getActualTypeArguments();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return actualTypeArguments[indexOfActualTypeArgument];
|
|
||||||
}
|
|
||||||
|
|
||||||
Type searchedType = null;
|
|
||||||
if (superClass != null) {
|
|
||||||
searchedType = extractTypeForHierarchy(superClass, typeToEvaluate);
|
|
||||||
}
|
|
||||||
return searchedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type[] extractRealTypes(
|
|
||||||
Type[] actualTypeArguments, Type parentType, Class<?> rawParentClass) {
|
|
||||||
Preconditions.checkNotNull(actualTypeArguments);
|
|
||||||
|
|
||||||
Type[] retTypes = new Type[actualTypeArguments.length];
|
|
||||||
for (int i = 0; i < actualTypeArguments.length; ++i) {
|
|
||||||
retTypes[i] = getActualType(actualTypeArguments[i], parentType, rawParentClass);
|
|
||||||
}
|
|
||||||
return retTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getIndex(TypeVariable<?>[] types, TypeVariable<?> type) {
|
|
||||||
for (int i = 0; i < types.length; ++i) {
|
|
||||||
if (type.equals(types[i])) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"How can the type variable not be present in the class declaration!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A convenience object for retrieving the map type information.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class TypeInfoMap {
|
|
||||||
private final Type keyType;
|
|
||||||
private final Type valueType;
|
|
||||||
|
|
||||||
public TypeInfoMap(Type mapType) {
|
|
||||||
if (mapType instanceof Class<?> && Properties.class.isAssignableFrom((Class<?>) mapType)) {
|
|
||||||
keyType = String.class;
|
|
||||||
valueType = String.class;
|
|
||||||
} else if (mapType instanceof ParameterizedType) {
|
|
||||||
TypeInfo rawType = new TypeInfo(mapType);
|
|
||||||
Preconditions.checkArgument(Map.class.isAssignableFrom(rawType.getRawClass()));
|
|
||||||
ParameterizedType paramType = (ParameterizedType) mapType;
|
|
||||||
keyType = paramType.getActualTypeArguments()[0];
|
|
||||||
valueType = paramType.getActualTypeArguments()[1];
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Map objects need to be parameterized unless you use a custom serializer. "
|
|
||||||
+ "Use the com.bukkit.mcteam.gson.reflect.TypeToken to extract the ParameterizedType.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getKeyType() {
|
|
||||||
return keyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getValueType() {
|
|
||||||
return valueType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.lang.reflect.GenericArrayType;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.lang.reflect.WildcardType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class containing some methods for obtaining information on types.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class TypeUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the actual type matching up with the first type variable.
|
|
||||||
* So, for a {@code typeInfo} instance defined as:
|
|
||||||
* <pre>
|
|
||||||
* class Foo<A, B> {
|
|
||||||
* }
|
|
||||||
* Type fooType = new TypeToken<Foo<Integer, String>>() {}.getType();
|
|
||||||
* </pre>
|
|
||||||
* <code>TypeUtils.getActualTypeForFirstTypeVariable(fooType)</code> 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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}.
|
|
||||||
*
|
|
||||||
*<p>The following is an example:</p>
|
|
||||||
* <pre>
|
|
||||||
* class StringWrapper {
|
|
||||||
* public String AStringField = "abcd";
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* UpperCamelCaseSeparatorNamingPolicy policy = new UpperCamelCaseSeparatorNamingPolicy("_");
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(StringWrapper.class.getField("AStringField"));
|
|
||||||
*
|
|
||||||
* assert("A_String_Field".equals(translatedFieldName));
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class UpperCamelCaseSeparatorNamingPolicy extends CompositionFieldNamingPolicy {
|
|
||||||
|
|
||||||
public UpperCamelCaseSeparatorNamingPolicy(String separatorString) {
|
|
||||||
super(new CamelCaseSeparatorNamingPolicy(separatorString),
|
|
||||||
new ModifyFirstLetterNamingPolicy(ModifyFirstLetterNamingPolicy.LetterModifier.UPPER));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>The following is an example:</p>
|
|
||||||
* <pre>
|
|
||||||
* class IntWrapper {
|
|
||||||
* public int integerField = 0;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* UpperCaseNamingPolicy policy = new UpperCaseNamingPolicy();
|
|
||||||
* String translatedFieldName =
|
|
||||||
* policy.translateName(IntWrapper.class.getField("integerField"));
|
|
||||||
*
|
|
||||||
* assert("INTEGERFIELD".equals(translatedFieldName));
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class UpperCaseNamingPolicy extends RecursiveFieldNamingPolicy {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String translateName(String target, Type fieldType, Collection<Annotation> annotations) {
|
|
||||||
return target.toUpperCase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>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.</p>
|
|
||||||
*
|
|
||||||
* <p>Here is an example of how this annotation is meant to be used:
|
|
||||||
* <p><pre>
|
|
||||||
* public class User {
|
|
||||||
* @Expose private String firstName;
|
|
||||||
* @Expose(serialize = false) private String lastName;
|
|
||||||
* @Expose (serialize = false, deserialize = false) private String emailAddress;
|
|
||||||
* private String password;
|
|
||||||
* }
|
|
||||||
* </pre></p>
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>Note that another way to achieve the same effect would have been to just mark the
|
|
||||||
* {@code password} field as {@code transient}, and Gson would have excluded it even with default
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>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.</p>
|
|
||||||
*
|
|
||||||
* <p>Here is an example of how this annotation is meant to be used:</p>
|
|
||||||
* <pre>
|
|
||||||
* 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;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>The following shows the output that is generated when serializing an instance of the
|
|
||||||
* above example class:</p>
|
|
||||||
* <pre>
|
|
||||||
* SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b");
|
|
||||||
* Gson gson = new Gson();
|
|
||||||
* String jsonRepresentation = gson.toJson(objectToSerialize);
|
|
||||||
* System.out.println(jsonRepresentation);
|
|
||||||
*
|
|
||||||
* ===== OUTPUT =====
|
|
||||||
* {"name":"a","someOtherField":"b"}
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p>
|
|
||||||
*
|
|
||||||
* @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();
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>Here is an example of how this annotation is meant to be used:</p>
|
|
||||||
* <pre>
|
|
||||||
* public class User {
|
|
||||||
* private String firstName;
|
|
||||||
* private String lastName;
|
|
||||||
* @Since(1.0) private String emailAddress;
|
|
||||||
* @Since(1.0) private String password;
|
|
||||||
* @Since(1.1) private Address address;
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
|
|
||||||
* methods will use all the fields for serialization and deserialization. However, if you created
|
|
||||||
* 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}.</p>
|
|
||||||
*
|
|
||||||
* @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();
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>Here is an example of how this annotation is meant to be used:</p>
|
|
||||||
* <pre>
|
|
||||||
* public class User {
|
|
||||||
* private String firstName;
|
|
||||||
* private String lastName;
|
|
||||||
* @Until(1.1) private String emailAddress;
|
|
||||||
* @Until(1.1) private String password;
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>If you created Gson with {@code new Gson()}, the {@code toJson()} and {@code fromJson()}
|
|
||||||
* methods will use all the fields for serialization and deserialization. However, if you created
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
/**
|
|
||||||
* This package provides the {@link com.bukkit.mcteam.gson.Gson} class to convert Json to Java and
|
|
||||||
* vice-versa.
|
|
||||||
*
|
|
||||||
* <p>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).</p>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh, Joel Leitch
|
|
||||||
*/
|
|
||||||
package org.mcteam.ancientgates.gson;
|
|
||||||
@@ -1,375 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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 <code>Collection<Foo></code>, you can use:
|
|
||||||
* <p>
|
|
||||||
* <code>Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
|
|
||||||
* </code>
|
|
||||||
*
|
|
||||||
* <p>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<T> {
|
|
||||||
|
|
||||||
final Class<? super T> rawType;
|
|
||||||
final Type type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new type token. Derives represented class from type
|
|
||||||
* parameter.
|
|
||||||
*
|
|
||||||
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
|
|
||||||
* parameter in the anonymous class's type hierarchy so we can reconstitute
|
|
||||||
* it at runtime despite erasure.
|
|
||||||
*
|
|
||||||
* <p>For example:
|
|
||||||
* <code>
|
|
||||||
* {@literal TypeToken<List<String>> t = new TypeToken<List<String>>}(){}
|
|
||||||
* </code>
|
|
||||||
*/
|
|
||||||
@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> 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<Object>(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<String, Type>());
|
|
||||||
} 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<String, Type>());
|
|
||||||
}
|
|
||||||
// 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<String, Type> 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<String, Type>(typeVarMap))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interfaces didn't work, try the superclass.
|
|
||||||
Type sType = clazz.getGenericSuperclass();
|
|
||||||
if (isAssignableFrom(sType, to, new HashMap<String, Type>(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<String, Type> 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<String, Type> 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<Object>(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets type token for the given {@code Class} instance.
|
|
||||||
*/
|
|
||||||
public static <T> TypeToken<T> get(Class<T> type) {
|
|
||||||
return new SimpleTypeToken<T>(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private static class to not create more anonymous classes than
|
|
||||||
* necessary.
|
|
||||||
*/
|
|
||||||
private static class SimpleTypeToken<T> extends TypeToken<T> {
|
|
||||||
public SimpleTypeToken(Type type) {
|
|
||||||
super(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/**
|
|
||||||
* This package provides utility classes for finding type information for generic types.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh, Joel Leitch
|
|
||||||
*/
|
|
||||||
package org.mcteam.ancientgates.gson.reflect;
|
|
||||||
@@ -1,1121 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package 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 (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <h3>Parsing JSON</h3>
|
|
||||||
* To create a recursive descent parser your own JSON streams, first create an
|
|
||||||
* entry point method that creates a {@code JsonReader}.
|
|
||||||
*
|
|
||||||
* <p>Next, create handler methods for each structure in your JSON text. You'll
|
|
||||||
* need a method for each object type and for each array type.
|
|
||||||
* <ul>
|
|
||||||
* <li>Within <strong>array handling</strong> 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}.
|
|
||||||
* <li>Within <strong>object handling</strong> 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}.
|
|
||||||
* </ul>
|
|
||||||
* <p>When a nested object or array is encountered, delegate to the
|
|
||||||
* corresponding handler method.
|
|
||||||
*
|
|
||||||
* <p>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.
|
|
||||||
*
|
|
||||||
* <p>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()}.
|
|
||||||
*
|
|
||||||
* <h3>Example</h3>
|
|
||||||
* Suppose we'd like to parse a stream of messages such as the following: <pre> {@code
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* "id": 912345678901,
|
|
||||||
* "text": "How do I read a JSON stream in Java?",
|
|
||||||
* "geo": null,
|
|
||||||
* "user": {
|
|
||||||
* "name": "json_newb",
|
|
||||||
* "followers_count": 41
|
|
||||||
* }
|
|
||||||
* },
|
|
||||||
* {
|
|
||||||
* "id": 912345678902,
|
|
||||||
* "text": "@json_newb just use JsonReader!",
|
|
||||||
* "geo": [50.454722, -104.606667],
|
|
||||||
* "user": {
|
|
||||||
* "name": "jesse",
|
|
||||||
* "followers_count": 2
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ]}</pre>
|
|
||||||
* This code implements the parser for the above structure: <pre> {@code
|
|
||||||
*
|
|
||||||
* public List<Message> readJsonStream(InputStream in) throws IOException {
|
|
||||||
* JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
|
|
||||||
* return readMessagesArray(reader);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public List<Message> readMessagesArray(JsonReader reader) throws IOException {
|
|
||||||
* List<Message> messages = new ArrayList<Message>();
|
|
||||||
*
|
|
||||||
* 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<Double> 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<Double> readDoublesArray(JsonReader reader) throws IOException {
|
|
||||||
* List<Double> doubles = new ArrayList<Double>();
|
|
||||||
*
|
|
||||||
* 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);
|
|
||||||
* }}</pre>
|
|
||||||
*
|
|
||||||
* <h3>Number Handling</h3>
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <a name="nonexecuteprefix"/><h3>Non-Execute Prefix</h3>
|
|
||||||
* Web servers that serve private data using JSON may be vulnerable to <a
|
|
||||||
* href="http://en.wikipedia.org/wiki/JSON#Cross-site_request_forgery">Cross-site
|
|
||||||
* request forgery</a> attacks. In such an attack, a malicious site gains access
|
|
||||||
* to a private JSON file by executing it with an HTML {@code <script>} tag.
|
|
||||||
*
|
|
||||||
* <p>Prefixing JSON files with <code>")]}'\n"</code> makes them non-executable
|
|
||||||
* by {@code <script>} tags, disarming the attack. Since the prefix is malformed
|
|
||||||
* JSON, strict parsing fails when it is encountered. This class permits the
|
|
||||||
* non-execute prefix when {@link #setLenient(boolean) lenient parsing} is
|
|
||||||
* enabled.
|
|
||||||
*
|
|
||||||
* <p>Each {@code JsonReader} may be used to read a single JSON stream. Instances
|
|
||||||
* of this class are not thread safe.
|
|
||||||
*
|
|
||||||
* @author Jesse Wilson
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
public final class JsonReader implements Closeable {
|
|
||||||
|
|
||||||
/** The only non-execute prefix this parser permits */
|
|
||||||
private static final char[] NON_EXECUTE_PREFIX = ")]}'\n".toCharArray();
|
|
||||||
|
|
||||||
/** The input JSON. */
|
|
||||||
private final Reader in;
|
|
||||||
|
|
||||||
/** True to accept non-spec compliant JSON */
|
|
||||||
private boolean lenient = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use a manual buffer to easily read and unread upcoming characters, and
|
|
||||||
* also so we can create strings without an intermediate StringBuilder.
|
|
||||||
*/
|
|
||||||
private final char[] buffer = new char[1024];
|
|
||||||
private int pos = 0;
|
|
||||||
private int limit = 0;
|
|
||||||
|
|
||||||
private final List<JsonScope> stack = new ArrayList<JsonScope>();
|
|
||||||
{
|
|
||||||
push(JsonScope.EMPTY_DOCUMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if we've already read the next token. If we have, the string value
|
|
||||||
* for that token will be assigned to {@code value} if such a string value
|
|
||||||
* exists. And the token type will be assigned to {@code token} if the token
|
|
||||||
* type is known. The token type may be null for literals, since we derive
|
|
||||||
* that lazily.
|
|
||||||
*/
|
|
||||||
private boolean hasToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of the next token to be returned by {@link #peek} and {@link
|
|
||||||
* #advance}, or {@code null} if it is unknown and must first be derived
|
|
||||||
* from {@code value}. This value is undefined if {@code hasToken} is false.
|
|
||||||
*/
|
|
||||||
private JsonToken token;
|
|
||||||
|
|
||||||
/** The text of the next name. */
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/** The text of the next literal value. */
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
/** True if we're currently handling a skipValue() call. */
|
|
||||||
private boolean skipping = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance that reads a JSON-encoded stream from {@code in}.
|
|
||||||
*/
|
|
||||||
public JsonReader(Reader in) {
|
|
||||||
if (in == null) {
|
|
||||||
throw new NullPointerException("in == null");
|
|
||||||
}
|
|
||||||
this.in = in;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure this parser to be be liberal in what it accepts. By default,
|
|
||||||
* this parser is strict and only accepts JSON as specified by <a
|
|
||||||
* href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the
|
|
||||||
* parser to lenient causes it to ignore the following syntax errors:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>Streams that start with the <a href="#nonexecuteprefix">non-execute
|
|
||||||
* prefix</a>, <code>")]}'\n"</code>.
|
|
||||||
* <li>Streams that include multiple top-level values. With strict parsing,
|
|
||||||
* each stream must contain exactly one top-level value.
|
|
||||||
* <li>Top-level values of any type. With strict parsing, the top-level
|
|
||||||
* value must be an object or an array.
|
|
||||||
* <li>Numbers may be {@link Double#isNaN() NaNs} or {@link
|
|
||||||
* Double#isInfinite() infinities}.
|
|
||||||
* <li>End of line comments starting with {@code //} or {@code #} and
|
|
||||||
* ending with a newline character.
|
|
||||||
* <li>C-style comments starting with {@code /*} and ending with
|
|
||||||
* {@code *}{@code /}. Such comments may not be nested.
|
|
||||||
* <li>Names that are unquoted or {@code 'single quoted'}.
|
|
||||||
* <li>Strings that are unquoted or {@code 'single quoted'}.
|
|
||||||
* <li>Array elements separated by {@code ;} instead of {@code ,}.
|
|
||||||
* <li>Unnecessary array separators. These are interpreted as if null
|
|
||||||
* was the omitted value.
|
|
||||||
* <li>Names and values separated by {@code =} or {@code =>} instead of
|
|
||||||
* {@code :}.
|
|
||||||
* <li>Name/value pairs separated by {@code ;} instead of {@code ,}.
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public void setLenient(boolean lenient) {
|
|
||||||
this.lenient = lenient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this parser is liberal in what it accepts.
|
|
||||||
*/
|
|
||||||
public boolean isLenient() {
|
|
||||||
return lenient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token from the JSON stream and asserts that it is the
|
|
||||||
* beginning of a new array.
|
|
||||||
*/
|
|
||||||
public void beginArray() throws IOException {
|
|
||||||
expect(JsonToken.BEGIN_ARRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token from the JSON stream and asserts that it is the
|
|
||||||
* end of the current array.
|
|
||||||
*/
|
|
||||||
public void endArray() throws IOException {
|
|
||||||
expect(JsonToken.END_ARRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token from the JSON stream and asserts that it is the
|
|
||||||
* beginning of a new object.
|
|
||||||
*/
|
|
||||||
public void beginObject() throws IOException {
|
|
||||||
expect(JsonToken.BEGIN_OBJECT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token from the JSON stream and asserts that it is the
|
|
||||||
* end of the current array.
|
|
||||||
*/
|
|
||||||
public void endObject() throws IOException {
|
|
||||||
expect(JsonToken.END_OBJECT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes {@code expected}.
|
|
||||||
*/
|
|
||||||
private void expect(JsonToken expected) throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
if (token != expected) {
|
|
||||||
throw new IllegalStateException("Expected " + expected + " but was " + peek());
|
|
||||||
}
|
|
||||||
advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the current array or object has another element.
|
|
||||||
*/
|
|
||||||
public boolean hasNext() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type of the next token without consuming it.
|
|
||||||
*/
|
|
||||||
public JsonToken peek() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
|
|
||||||
if (token == null) {
|
|
||||||
decodeLiteral();
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures that a token is ready. After this call either {@code token} or
|
|
||||||
* {@code value} will be non-null. To ensure {@code token} has a definitive
|
|
||||||
* value, use {@link #peek()}
|
|
||||||
*/
|
|
||||||
private JsonToken quickPeek() throws IOException {
|
|
||||||
if (hasToken) {
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (peekStack()) {
|
|
||||||
case EMPTY_DOCUMENT:
|
|
||||||
if (lenient) {
|
|
||||||
consumeNonExecutePrefix();
|
|
||||||
}
|
|
||||||
replaceTop(JsonScope.NONEMPTY_DOCUMENT);
|
|
||||||
JsonToken firstToken = nextValue();
|
|
||||||
if (!lenient && firstToken != JsonToken.BEGIN_ARRAY && firstToken != JsonToken.BEGIN_OBJECT) {
|
|
||||||
syntaxError("Expected JSON document to start with '[' or '{'");
|
|
||||||
}
|
|
||||||
return firstToken;
|
|
||||||
case EMPTY_ARRAY:
|
|
||||||
return nextInArray(true);
|
|
||||||
case NONEMPTY_ARRAY:
|
|
||||||
return nextInArray(false);
|
|
||||||
case EMPTY_OBJECT:
|
|
||||||
return nextInObject(true);
|
|
||||||
case DANGLING_NAME:
|
|
||||||
return objectValue();
|
|
||||||
case NONEMPTY_OBJECT:
|
|
||||||
return nextInObject(false);
|
|
||||||
case NONEMPTY_DOCUMENT:
|
|
||||||
try {
|
|
||||||
JsonToken token = nextValue();
|
|
||||||
if (lenient) {
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
throw syntaxError("Expected EOF");
|
|
||||||
} catch (EOFException e) {
|
|
||||||
hasToken = true; // TODO: avoid throwing here?
|
|
||||||
return token = JsonToken.END_DOCUMENT;
|
|
||||||
}
|
|
||||||
case CLOSED:
|
|
||||||
throw new IllegalStateException("JsonReader is closed");
|
|
||||||
default:
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the non-execute prefix if it exists.
|
|
||||||
*/
|
|
||||||
private void consumeNonExecutePrefix() throws IOException {
|
|
||||||
// fast forward through the leading whitespace
|
|
||||||
nextNonWhitespace();
|
|
||||||
pos--;
|
|
||||||
|
|
||||||
if (pos + NON_EXECUTE_PREFIX.length > limit && !fillBuffer(NON_EXECUTE_PREFIX.length)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < NON_EXECUTE_PREFIX.length; i++) {
|
|
||||||
if (buffer[pos + i] != NON_EXECUTE_PREFIX[i]) {
|
|
||||||
return; // not a security token!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we consumed a security token!
|
|
||||||
pos += NON_EXECUTE_PREFIX.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances the cursor in the JSON stream to the next token.
|
|
||||||
*/
|
|
||||||
private JsonToken advance() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
|
|
||||||
JsonToken result = token;
|
|
||||||
hasToken = false;
|
|
||||||
token = null;
|
|
||||||
value = null;
|
|
||||||
name = null;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next token, a {@link JsonToken#NAME property name}, and
|
|
||||||
* consumes it.
|
|
||||||
*
|
|
||||||
* @throws IOException if the next token in the stream is not a property
|
|
||||||
* name.
|
|
||||||
*/
|
|
||||||
public String nextName() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
if (token != JsonToken.NAME) {
|
|
||||||
throw new IllegalStateException("Expected a name but was " + peek());
|
|
||||||
}
|
|
||||||
String result = name;
|
|
||||||
advance();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link JsonToken#STRING string} value of the next token,
|
|
||||||
* consuming it. If the next token is a number, this method will return its
|
|
||||||
* string form.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if the next token is not a string or if
|
|
||||||
* this reader is closed.
|
|
||||||
*/
|
|
||||||
public String nextString() throws IOException {
|
|
||||||
peek();
|
|
||||||
if (value == null || (token != JsonToken.STRING && token != JsonToken.NUMBER)) {
|
|
||||||
throw new IllegalStateException("Expected a string but was " + peek());
|
|
||||||
}
|
|
||||||
|
|
||||||
String result = value;
|
|
||||||
advance();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link JsonToken#BOOLEAN boolean} value of the next token,
|
|
||||||
* consuming it.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if the next token is not a boolean or if
|
|
||||||
* this reader is closed.
|
|
||||||
*/
|
|
||||||
public boolean nextBoolean() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
if (value == null || token == JsonToken.STRING) {
|
|
||||||
throw new IllegalStateException("Expected a boolean but was " + peek());
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean result;
|
|
||||||
if (value.equalsIgnoreCase("true")) {
|
|
||||||
result = true;
|
|
||||||
} else if (value.equalsIgnoreCase("false")) {
|
|
||||||
result = false;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Not a boolean: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
advance();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Consumes the next token from the JSON stream and asserts that it is a
|
|
||||||
* literal null.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if the next token is not null or if this
|
|
||||||
* reader is closed.
|
|
||||||
*/
|
|
||||||
public void nextNull() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
if (value == null || token == JsonToken.STRING) {
|
|
||||||
throw new IllegalStateException("Expected null but was " + peek());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value.equalsIgnoreCase("null")) {
|
|
||||||
throw new IllegalStateException("Not a null: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
advance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link JsonToken#NUMBER double} value of the next token,
|
|
||||||
* consuming it. If the next token is a string, this method will attempt to
|
|
||||||
* parse it as a double.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if the next token is not a literal value.
|
|
||||||
* @throws NumberFormatException if the next literal value cannot be parsed
|
|
||||||
* as a double, or is non-finite.
|
|
||||||
*/
|
|
||||||
public double nextDouble() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
if (value == null) {
|
|
||||||
throw new IllegalStateException("Expected a double but was " + peek());
|
|
||||||
}
|
|
||||||
|
|
||||||
double result = Double.parseDouble(value);
|
|
||||||
|
|
||||||
if ((result >= 1.0d && value.startsWith("0"))) {
|
|
||||||
throw new NumberFormatException("JSON forbids octal prefixes: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {
|
|
||||||
throw new NumberFormatException("JSON forbids NaN and infinities: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
advance();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link JsonToken#NUMBER long} value of the next token,
|
|
||||||
* consuming it. If the next token is a string, this method will attempt to
|
|
||||||
* parse it as a long. If the next token's numeric value cannot be exactly
|
|
||||||
* represented by a Java {@code long}, this method throws.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if the next token is not a literal value.
|
|
||||||
* @throws NumberFormatException if the next literal value cannot be parsed
|
|
||||||
* as a number, or exactly represented as a long.
|
|
||||||
*/
|
|
||||||
public long nextLong() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
if (value == null) {
|
|
||||||
throw new IllegalStateException("Expected a long but was " + peek());
|
|
||||||
}
|
|
||||||
|
|
||||||
long result;
|
|
||||||
try {
|
|
||||||
result = Long.parseLong(value);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
|
|
||||||
result = (long) asDouble;
|
|
||||||
if (result != asDouble) {
|
|
||||||
throw new NumberFormatException(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result >= 1L && value.startsWith("0")) {
|
|
||||||
throw new NumberFormatException("JSON forbids octal prefixes: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
advance();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link JsonToken#NUMBER int} value of the next token,
|
|
||||||
* consuming it. If the next token is a string, this method will attempt to
|
|
||||||
* parse it as an int. If the next token's numeric value cannot be exactly
|
|
||||||
* represented by a Java {@code int}, this method throws.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if the next token is not a literal value.
|
|
||||||
* @throws NumberFormatException if the next literal value cannot be parsed
|
|
||||||
* as a number, or exactly represented as an int.
|
|
||||||
*/
|
|
||||||
public int nextInt() throws IOException {
|
|
||||||
quickPeek();
|
|
||||||
if (value == null) {
|
|
||||||
throw new IllegalStateException("Expected an int but was " + peek());
|
|
||||||
}
|
|
||||||
|
|
||||||
int result;
|
|
||||||
try {
|
|
||||||
result = Integer.parseInt(value);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
double asDouble = Double.parseDouble(value); // don't catch this NumberFormatException
|
|
||||||
result = (int) asDouble;
|
|
||||||
if (result != asDouble) {
|
|
||||||
throw new NumberFormatException(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result >= 1L && value.startsWith("0")) {
|
|
||||||
throw new NumberFormatException("JSON forbids octal prefixes: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
advance();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes this JSON reader and the underlying {@link Reader}.
|
|
||||||
*/
|
|
||||||
public void close() throws IOException {
|
|
||||||
hasToken = false;
|
|
||||||
value = null;
|
|
||||||
token = null;
|
|
||||||
stack.clear();
|
|
||||||
stack.add(JsonScope.CLOSED);
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skips the next value recursively. If it is an object or array, all nested
|
|
||||||
* elements are skipped. This method is intended for use when the JSON token
|
|
||||||
* stream contains unrecognized or unhandled values.
|
|
||||||
*/
|
|
||||||
public void skipValue() throws IOException {
|
|
||||||
skipping = true;
|
|
||||||
try {
|
|
||||||
int count = 0;
|
|
||||||
do {
|
|
||||||
JsonToken token = advance();
|
|
||||||
if (token == JsonToken.BEGIN_ARRAY || token == JsonToken.BEGIN_OBJECT) {
|
|
||||||
count++;
|
|
||||||
} else if (token == JsonToken.END_ARRAY || token == JsonToken.END_OBJECT) {
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
} while (count != 0);
|
|
||||||
} finally {
|
|
||||||
skipping = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonScope peekStack() {
|
|
||||||
return stack.get(stack.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonScope pop() {
|
|
||||||
return stack.remove(stack.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void push(JsonScope newTop) {
|
|
||||||
stack.add(newTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the value on the top of the stack with the given value.
|
|
||||||
*/
|
|
||||||
private void replaceTop(JsonScope newTop) {
|
|
||||||
stack.set(stack.size() - 1, newTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("fallthrough")
|
|
||||||
private JsonToken nextInArray(boolean firstElement) throws IOException {
|
|
||||||
if (firstElement) {
|
|
||||||
replaceTop(JsonScope.NONEMPTY_ARRAY);
|
|
||||||
} else {
|
|
||||||
/* Look for a comma before each element after the first element. */
|
|
||||||
switch (nextNonWhitespace()) {
|
|
||||||
case ']':
|
|
||||||
pop();
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.END_ARRAY;
|
|
||||||
case ';':
|
|
||||||
checkLenient(); // fall-through
|
|
||||||
case ',':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw syntaxError("Unterminated array");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (nextNonWhitespace()) {
|
|
||||||
case ']':
|
|
||||||
if (firstElement) {
|
|
||||||
pop();
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.END_ARRAY;
|
|
||||||
}
|
|
||||||
// fall-through to handle ",]"
|
|
||||||
case ';':
|
|
||||||
case ',':
|
|
||||||
/* In lenient mode, a 0-length literal means 'null' */
|
|
||||||
checkLenient();
|
|
||||||
pos--;
|
|
||||||
hasToken = true;
|
|
||||||
value = "null";
|
|
||||||
return token = JsonToken.NULL;
|
|
||||||
default:
|
|
||||||
pos--;
|
|
||||||
return nextValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("fallthrough")
|
|
||||||
private JsonToken nextInObject(boolean firstElement) throws IOException {
|
|
||||||
/*
|
|
||||||
* Read delimiters. Either a comma/semicolon separating this and the
|
|
||||||
* previous name-value pair, or a close brace to denote the end of the
|
|
||||||
* object.
|
|
||||||
*/
|
|
||||||
if (firstElement) {
|
|
||||||
/* Peek to see if this is the empty object. */
|
|
||||||
switch (nextNonWhitespace()) {
|
|
||||||
case '}':
|
|
||||||
pop();
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.END_OBJECT;
|
|
||||||
default:
|
|
||||||
pos--;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (nextNonWhitespace()) {
|
|
||||||
case '}':
|
|
||||||
pop();
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.END_OBJECT;
|
|
||||||
case ';':
|
|
||||||
case ',':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw syntaxError("Unterminated object");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read the name. */
|
|
||||||
int quote = nextNonWhitespace();
|
|
||||||
switch (quote) {
|
|
||||||
case '\'':
|
|
||||||
checkLenient(); // fall-through
|
|
||||||
case '"':
|
|
||||||
name = nextString((char) quote);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
checkLenient();
|
|
||||||
pos--;
|
|
||||||
name = nextLiteral();
|
|
||||||
if (name.length() == 0) {
|
|
||||||
throw syntaxError("Expected name");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceTop(JsonScope.DANGLING_NAME);
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonToken objectValue() throws IOException {
|
|
||||||
/*
|
|
||||||
* Read the name/value separator. Usually a colon ':'. In lenient mode
|
|
||||||
* we also accept an equals sign '=', or an arrow "=>".
|
|
||||||
*/
|
|
||||||
switch (nextNonWhitespace()) {
|
|
||||||
case ':':
|
|
||||||
break;
|
|
||||||
case '=':
|
|
||||||
checkLenient();
|
|
||||||
if ((pos < limit || fillBuffer(1)) && buffer[pos] == '>') {
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw syntaxError("Expected ':'");
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceTop(JsonScope.NONEMPTY_OBJECT);
|
|
||||||
return nextValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("fallthrough")
|
|
||||||
private JsonToken nextValue() throws IOException {
|
|
||||||
int c = nextNonWhitespace();
|
|
||||||
switch (c) {
|
|
||||||
case '{':
|
|
||||||
push(JsonScope.EMPTY_OBJECT);
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.BEGIN_OBJECT;
|
|
||||||
|
|
||||||
case '[':
|
|
||||||
push(JsonScope.EMPTY_ARRAY);
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.BEGIN_ARRAY;
|
|
||||||
|
|
||||||
case '\'':
|
|
||||||
checkLenient(); // fall-through
|
|
||||||
case '"':
|
|
||||||
value = nextString((char) c);
|
|
||||||
hasToken = true;
|
|
||||||
return token = JsonToken.STRING;
|
|
||||||
|
|
||||||
default:
|
|
||||||
pos--;
|
|
||||||
return readLiteral();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true once {@code limit - pos >= minimum}. If the data is
|
|
||||||
* exhausted before that many characters are available, this returns
|
|
||||||
* false.
|
|
||||||
*/
|
|
||||||
private boolean fillBuffer(int minimum) throws IOException {
|
|
||||||
if (limit != pos) {
|
|
||||||
limit -= pos;
|
|
||||||
System.arraycopy(buffer, pos, buffer, 0, limit);
|
|
||||||
} else {
|
|
||||||
limit = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = 0;
|
|
||||||
int total;
|
|
||||||
while ((total = in.read(buffer, limit, buffer.length - limit)) != -1) {
|
|
||||||
limit += total;
|
|
||||||
if (limit >= minimum) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int nextNonWhitespace() throws IOException {
|
|
||||||
while (pos < limit || fillBuffer(1)) {
|
|
||||||
int c = buffer[pos++];
|
|
||||||
switch (c) {
|
|
||||||
case '\t':
|
|
||||||
case ' ':
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case '/':
|
|
||||||
if (pos == limit && !fillBuffer(1)) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkLenient();
|
|
||||||
char peek = buffer[pos];
|
|
||||||
switch (peek) {
|
|
||||||
case '*':
|
|
||||||
// skip a /* c-style comment */
|
|
||||||
pos++;
|
|
||||||
if (!skipTo("*/")) {
|
|
||||||
throw syntaxError("Unterminated comment");
|
|
||||||
}
|
|
||||||
pos += 2;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case '/':
|
|
||||||
// skip a // end-of-line comment
|
|
||||||
pos++;
|
|
||||||
skipToEndOfLine();
|
|
||||||
continue;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
case '#':
|
|
||||||
/*
|
|
||||||
* Skip a # hash end-of-line comment. The JSON RFC doesn't
|
|
||||||
* specify this behaviour, but it's required to parse
|
|
||||||
* existing documents. See http://b/2571423.
|
|
||||||
*/
|
|
||||||
checkLenient();
|
|
||||||
skipToEndOfLine();
|
|
||||||
continue;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new EOFException("End of input");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkLenient() throws IOException {
|
|
||||||
if (!lenient) {
|
|
||||||
throw syntaxError("Use JsonReader.setLenient(true) to accept malformed JSON");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances the position until after the next newline character. If the line
|
|
||||||
* is terminated by "\r\n", the '\n' must be consumed as whitespace by the
|
|
||||||
* caller.
|
|
||||||
*/
|
|
||||||
private void skipToEndOfLine() throws IOException {
|
|
||||||
while (pos < limit || fillBuffer(1)) {
|
|
||||||
char c = buffer[pos++];
|
|
||||||
if (c == '\r' || c == '\n') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean skipTo(String toFind) throws IOException {
|
|
||||||
outer:
|
|
||||||
for (; pos + toFind.length() < limit || fillBuffer(toFind.length()); pos++) {
|
|
||||||
for (int c = 0; c < toFind.length(); c++) {
|
|
||||||
if (buffer[pos + c] != toFind.charAt(c)) {
|
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string up to but not including {@code quote}, unescaping any
|
|
||||||
* character escape sequences encountered along the way. The opening quote
|
|
||||||
* should have already been read. This consumes the closing quote, but does
|
|
||||||
* not include it in the returned string.
|
|
||||||
*
|
|
||||||
* @param quote either ' or ".
|
|
||||||
* @throws NumberFormatException if any unicode escape sequences are
|
|
||||||
* malformed.
|
|
||||||
*/
|
|
||||||
private String nextString(char quote) throws IOException {
|
|
||||||
StringBuilder builder = null;
|
|
||||||
do {
|
|
||||||
/* the index of the first character not yet appended to the builder. */
|
|
||||||
int start = pos;
|
|
||||||
while (pos < limit) {
|
|
||||||
int c = buffer[pos++];
|
|
||||||
|
|
||||||
if (c == quote) {
|
|
||||||
if (skipping) {
|
|
||||||
return "skipped!";
|
|
||||||
} else if (builder == null) {
|
|
||||||
return new String(buffer, start, pos - start - 1);
|
|
||||||
} else {
|
|
||||||
builder.append(buffer, start, pos - start - 1);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (c == '\\') {
|
|
||||||
if (builder == null) {
|
|
||||||
builder = new StringBuilder();
|
|
||||||
}
|
|
||||||
builder.append(buffer, start, pos - start - 1);
|
|
||||||
builder.append(readEscapeCharacter());
|
|
||||||
start = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (builder == null) {
|
|
||||||
builder = new StringBuilder();
|
|
||||||
}
|
|
||||||
builder.append(buffer, start, pos - start);
|
|
||||||
} while (fillBuffer(1));
|
|
||||||
|
|
||||||
throw syntaxError("Unterminated string");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string up to but not including any delimiter characters. This
|
|
||||||
* does not consume the delimiter character.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("fallthrough")
|
|
||||||
private String nextLiteral() throws IOException {
|
|
||||||
StringBuilder builder = null;
|
|
||||||
do {
|
|
||||||
/* the index of the first character not yet appended to the builder. */
|
|
||||||
int start = pos;
|
|
||||||
while (pos < limit) {
|
|
||||||
int c = buffer[pos++];
|
|
||||||
switch (c) {
|
|
||||||
case '/':
|
|
||||||
case '\\':
|
|
||||||
case ';':
|
|
||||||
case '#':
|
|
||||||
case '=':
|
|
||||||
checkLenient(); // fall-through
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
case ':':
|
|
||||||
case ',':
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\f':
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
pos--;
|
|
||||||
if (skipping) {
|
|
||||||
return "skipped!";
|
|
||||||
} else if (builder == null) {
|
|
||||||
return new String(buffer, start, pos - start);
|
|
||||||
} else {
|
|
||||||
builder.append(buffer, start, pos - start);
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (builder == null) {
|
|
||||||
builder = new StringBuilder();
|
|
||||||
}
|
|
||||||
builder.append(buffer, start, pos - start);
|
|
||||||
} while (fillBuffer(1));
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return getClass().getSimpleName() + " near " + getSnippet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unescapes the character identified by the character or characters that
|
|
||||||
* immediately follow a backslash. The backslash '\' should have already
|
|
||||||
* been read. This supports both unicode escapes "u000A" and two-character
|
|
||||||
* escapes "\n".
|
|
||||||
*
|
|
||||||
* @throws NumberFormatException if any unicode escape sequences are
|
|
||||||
* malformed.
|
|
||||||
*/
|
|
||||||
private char readEscapeCharacter() throws IOException {
|
|
||||||
if (pos == limit && !fillBuffer(1)) {
|
|
||||||
throw syntaxError("Unterminated escape sequence");
|
|
||||||
}
|
|
||||||
|
|
||||||
char escaped = buffer[pos++];
|
|
||||||
switch (escaped) {
|
|
||||||
case 'u':
|
|
||||||
if (pos + 4 > limit && !fillBuffer(4)) {
|
|
||||||
throw syntaxError("Unterminated escape sequence");
|
|
||||||
}
|
|
||||||
String hex = new String(buffer, pos, 4);
|
|
||||||
pos += 4;
|
|
||||||
return (char) Integer.parseInt(hex, 16);
|
|
||||||
|
|
||||||
case 't':
|
|
||||||
return '\t';
|
|
||||||
|
|
||||||
case 'b':
|
|
||||||
return '\b';
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
return '\n';
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
return '\r';
|
|
||||||
|
|
||||||
case 'f':
|
|
||||||
return '\f';
|
|
||||||
|
|
||||||
case '\'':
|
|
||||||
case '"':
|
|
||||||
case '\\':
|
|
||||||
default:
|
|
||||||
return escaped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads a null, boolean, numeric or unquoted string literal value.
|
|
||||||
*/
|
|
||||||
private JsonToken readLiteral() throws IOException {
|
|
||||||
String literal = nextLiteral();
|
|
||||||
if (literal.length() == 0) {
|
|
||||||
throw syntaxError("Expected literal value");
|
|
||||||
}
|
|
||||||
value = literal;
|
|
||||||
hasToken = true;
|
|
||||||
return token = null; // use decodeLiteral() to get the token type
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigns {@code nextToken} based on the value of {@code nextValue}.
|
|
||||||
*/
|
|
||||||
private void decodeLiteral() throws IOException {
|
|
||||||
if (value.equalsIgnoreCase("null")) {
|
|
||||||
token = JsonToken.NULL;
|
|
||||||
} else if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
|
|
||||||
token = JsonToken.BOOLEAN;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
Double.parseDouble(value); // this work could potentially be cached
|
|
||||||
token = JsonToken.NUMBER;
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
// this must be an unquoted string
|
|
||||||
throw syntaxError("invalid number or unquoted string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Throws a new IO exception with the given message and a context snippet
|
|
||||||
* with this reader's content.
|
|
||||||
*/
|
|
||||||
private IOException syntaxError(String message) throws IOException {
|
|
||||||
throw new MalformedJsonException(message + " near " + getSnippet());
|
|
||||||
}
|
|
||||||
|
|
||||||
private CharSequence getSnippet() {
|
|
||||||
StringBuilder snippet = new StringBuilder();
|
|
||||||
int beforePos = Math.min(pos, 20);
|
|
||||||
snippet.append(buffer, pos - beforePos, beforePos);
|
|
||||||
int afterPos = Math.min(limit - pos, 20);
|
|
||||||
snippet.append(buffer, pos, afterPos);
|
|
||||||
return snippet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson.stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lexical scoping elements within a JSON reader or writer.
|
|
||||||
*
|
|
||||||
* @author Jesse Wilson
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
enum JsonScope {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array with no elements requires no separators or newlines before
|
|
||||||
* it is closed.
|
|
||||||
*/
|
|
||||||
EMPTY_ARRAY,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A array with at least one value requires a comma and newline before
|
|
||||||
* the next element.
|
|
||||||
*/
|
|
||||||
NONEMPTY_ARRAY,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An object with no name/value pairs requires no separators or newlines
|
|
||||||
* before it is closed.
|
|
||||||
*/
|
|
||||||
EMPTY_OBJECT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An object whose most recent element is a key. The next element must
|
|
||||||
* be a value.
|
|
||||||
*/
|
|
||||||
DANGLING_NAME,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An object with at least one name/value pair requires a comma and
|
|
||||||
* newline before the next element.
|
|
||||||
*/
|
|
||||||
NONEMPTY_OBJECT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No object or array has been started.
|
|
||||||
*/
|
|
||||||
EMPTY_DOCUMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A document with at an array or object.
|
|
||||||
*/
|
|
||||||
NONEMPTY_DOCUMENT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A document that's been closed and cannot be accessed.
|
|
||||||
*/
|
|
||||||
CLOSED,
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson.stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A structure, name or value type in a JSON-encoded string.
|
|
||||||
*
|
|
||||||
* @author Jesse Wilson
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
public enum JsonToken {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The opening of a JSON array. Written using {@link JsonWriter#beginObject}
|
|
||||||
* and read using {@link JsonReader#beginObject}.
|
|
||||||
*/
|
|
||||||
BEGIN_ARRAY,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The closing of a JSON array. Written using {@link JsonWriter#endArray}
|
|
||||||
* and read using {@link JsonReader#endArray}.
|
|
||||||
*/
|
|
||||||
END_ARRAY,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The opening of a JSON object. Written using {@link JsonWriter#beginObject}
|
|
||||||
* and read using {@link JsonReader#beginObject}.
|
|
||||||
*/
|
|
||||||
BEGIN_OBJECT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The closing of a JSON object. Written using {@link JsonWriter#endObject}
|
|
||||||
* and read using {@link JsonReader#endObject}.
|
|
||||||
*/
|
|
||||||
END_OBJECT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A JSON property name. Within objects, tokens alternate between names and
|
|
||||||
* their values. Written using {@link JsonWriter#name} and read using {@link
|
|
||||||
* JsonReader#nextName}
|
|
||||||
*/
|
|
||||||
NAME,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A JSON string.
|
|
||||||
*/
|
|
||||||
STRING,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A JSON number represented in this API by a Java {@code double}, {@code
|
|
||||||
* long}, or {@code int}.
|
|
||||||
*/
|
|
||||||
NUMBER,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A JSON {@code true} or {@code false}.
|
|
||||||
*/
|
|
||||||
BOOLEAN,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A JSON {@code null}.
|
|
||||||
*/
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The end of the JSON stream. This sentinel value is returned by {@link
|
|
||||||
* JsonReader#peek()} to signal that the JSON-encoded value has no more
|
|
||||||
* tokens.
|
|
||||||
*/
|
|
||||||
END_DOCUMENT
|
|
||||||
}
|
|
||||||
@@ -1,553 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson.stream;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
|
|
||||||
* encoded value to a stream, one token at a time. The stream includes both
|
|
||||||
* literal values (strings, numbers, booleans and nulls) as well as the begin
|
|
||||||
* and end delimiters of objects and arrays.
|
|
||||||
*
|
|
||||||
* <h3>Encoding JSON</h3>
|
|
||||||
* To encode your data as JSON, create a new {@code JsonWriter}. Each JSON
|
|
||||||
* document must contain one top-level array or object. Call methods on the
|
|
||||||
* writer as you walk the structure's contents, nesting arrays and objects as
|
|
||||||
* necessary:
|
|
||||||
* <ul>
|
|
||||||
* <li>To write <strong>arrays</strong>, first call {@link #beginArray()}.
|
|
||||||
* Write each of the array's elements with the appropriate {@link #value}
|
|
||||||
* methods or by nesting other arrays and objects. Finally close the array
|
|
||||||
* using {@link #endArray()}.
|
|
||||||
* <li>To write <strong>objects</strong>, first call {@link #beginObject()}.
|
|
||||||
* Write each of the object's properties by alternating calls to
|
|
||||||
* {@link #name} with the property's value. Write property values with the
|
|
||||||
* appropriate {@link #value} method or by nesting other objects or arrays.
|
|
||||||
* Finally close the object using {@link #endObject()}.
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* <h3>Example</h3>
|
|
||||||
* Suppose we'd like to encode a stream of messages such as the following: <pre> {@code
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* "id": 912345678901,
|
|
||||||
* "text": "How do I stream JSON in Java?",
|
|
||||||
* "geo": null,
|
|
||||||
* "user": {
|
|
||||||
* "name": "json_newb",
|
|
||||||
* "followers_count": 41
|
|
||||||
* }
|
|
||||||
* },
|
|
||||||
* {
|
|
||||||
* "id": 912345678902,
|
|
||||||
* "text": "@json_newb just use JsonWriter!",
|
|
||||||
* "geo": [50.454722, -104.606667],
|
|
||||||
* "user": {
|
|
||||||
* "name": "jesse",
|
|
||||||
* "followers_count": 2
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ]}</pre>
|
|
||||||
* This code encodes the above structure: <pre> {@code
|
|
||||||
* public void writeJsonStream(OutputStream out, List<Message> messages) throws IOException {
|
|
||||||
* JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
|
|
||||||
* writer.setIndentSpaces(4);
|
|
||||||
* writeMessagesArray(writer, messages);
|
|
||||||
* writer.close();
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public void writeMessagesArray(JsonWriter writer, List<Message> messages) throws IOException {
|
|
||||||
* writer.beginArray();
|
|
||||||
* for (Message message : messages) {
|
|
||||||
* writeMessage(writer, message);
|
|
||||||
* }
|
|
||||||
* writer.endArray();
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public void writeMessage(JsonWriter writer, Message message) throws IOException {
|
|
||||||
* writer.beginObject();
|
|
||||||
* writer.name("id").value(message.getId());
|
|
||||||
* writer.name("text").value(message.getText());
|
|
||||||
* if (message.getGeo() != null) {
|
|
||||||
* writer.name("geo");
|
|
||||||
* writeDoublesArray(writer, message.getGeo());
|
|
||||||
* } else {
|
|
||||||
* writer.name("geo").nullValue();
|
|
||||||
* }
|
|
||||||
* writer.name("user");
|
|
||||||
* writeUser(writer, message.getUser());
|
|
||||||
* writer.endObject();
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public void writeUser(JsonWriter writer, User user) throws IOException {
|
|
||||||
* writer.beginObject();
|
|
||||||
* writer.name("name").value(user.getName());
|
|
||||||
* writer.name("followers_count").value(user.getFollowersCount());
|
|
||||||
* writer.endObject();
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public void writeDoublesArray(JsonWriter writer, List<Double> doubles) throws IOException {
|
|
||||||
* writer.beginArray();
|
|
||||||
* for (Double value : doubles) {
|
|
||||||
* writer.value(value);
|
|
||||||
* }
|
|
||||||
* writer.endArray();
|
|
||||||
* }}</pre>
|
|
||||||
*
|
|
||||||
* <p>Each {@code JsonWriter} may be used to write a single JSON stream.
|
|
||||||
* Instances of this class are not thread safe. Calls that would result in a
|
|
||||||
* malformed JSON string will fail with an {@link IllegalStateException}.
|
|
||||||
*
|
|
||||||
* @author Jesse Wilson
|
|
||||||
* @since 1.6
|
|
||||||
*/
|
|
||||||
public final class JsonWriter implements Closeable {
|
|
||||||
|
|
||||||
/** The output data, containing at most one top-level array or object. */
|
|
||||||
private final Writer out;
|
|
||||||
|
|
||||||
private final List<JsonScope> stack = new ArrayList<JsonScope>();
|
|
||||||
{
|
|
||||||
stack.add(JsonScope.EMPTY_DOCUMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A string containing a full set of spaces for a single level of
|
|
||||||
* indentation, or null for no pretty printing.
|
|
||||||
*/
|
|
||||||
private String indent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name/value separator; either ":" or ": ".
|
|
||||||
*/
|
|
||||||
private String separator = ":";
|
|
||||||
|
|
||||||
private boolean lenient;
|
|
||||||
|
|
||||||
private boolean htmlSafe;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance that writes a JSON-encoded stream to {@code out}.
|
|
||||||
* For best performance, ensure {@link Writer} is buffered; wrapping in
|
|
||||||
* {@link java.io.BufferedWriter BufferedWriter} if necessary.
|
|
||||||
*/
|
|
||||||
public JsonWriter(Writer out) {
|
|
||||||
if (out == null) {
|
|
||||||
throw new NullPointerException("out == null");
|
|
||||||
}
|
|
||||||
this.out = out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the indentation string to be repeated for each level of indentation
|
|
||||||
* in the encoded document. If {@code indent.isEmpty()} the encoded document
|
|
||||||
* will be compact. Otherwise the encoded document will be more
|
|
||||||
* human-readable.
|
|
||||||
*
|
|
||||||
* @param indent a string containing only whitespace.
|
|
||||||
*/
|
|
||||||
public void setIndent(String indent) {
|
|
||||||
if (indent.length() == 0) {
|
|
||||||
this.indent = null;
|
|
||||||
this.separator = ":";
|
|
||||||
} else {
|
|
||||||
this.indent = indent;
|
|
||||||
this.separator = ": ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure this writer to relax its syntax rules. By default, this writer
|
|
||||||
* only emits well-formed JSON as specified by <a
|
|
||||||
* href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the writer
|
|
||||||
* to lenient permits the following:
|
|
||||||
* <ul>
|
|
||||||
* <li>Top-level values of any type. With strict writing, the top-level
|
|
||||||
* value must be an object or an array.
|
|
||||||
* <li>Numbers may be {@link Double#isNaN() NaNs} or {@link
|
|
||||||
* Double#isInfinite() infinities}.
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public void setLenient(boolean lenient) {
|
|
||||||
this.lenient = lenient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this writer has relaxed syntax rules.
|
|
||||||
*/
|
|
||||||
public boolean isLenient() {
|
|
||||||
return lenient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure this writer to emit JSON that's safe for direct inclusion in HTML
|
|
||||||
* and XML documents. This escapes the HTML characters {@code <}, {@code >},
|
|
||||||
* {@code &} and {@code =} before writing them to the stream. Without this
|
|
||||||
* setting, your XML/HTML encoder should replace these characters with the
|
|
||||||
* corresponding escape sequences.
|
|
||||||
*/
|
|
||||||
public void setHtmlSafe(boolean htmlSafe) {
|
|
||||||
this.htmlSafe = htmlSafe;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this writer writes JSON that's safe for inclusion in HTML
|
|
||||||
* and XML documents.
|
|
||||||
*/
|
|
||||||
public boolean isHtmlSafe() {
|
|
||||||
return htmlSafe;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begins encoding a new array. Each call to this method must be paired with
|
|
||||||
* a call to {@link #endArray}.
|
|
||||||
*
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter beginArray() throws IOException {
|
|
||||||
return open(JsonScope.EMPTY_ARRAY, "[");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ends encoding the current array.
|
|
||||||
*
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter endArray() throws IOException {
|
|
||||||
return close(JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY, "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begins encoding a new object. Each call to this method must be paired
|
|
||||||
* with a call to {@link #endObject}.
|
|
||||||
*
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter beginObject() throws IOException {
|
|
||||||
return open(JsonScope.EMPTY_OBJECT, "{");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ends encoding the current object.
|
|
||||||
*
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter endObject() throws IOException {
|
|
||||||
return close(JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT, "}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enters a new scope by appending any necessary whitespace and the given
|
|
||||||
* bracket.
|
|
||||||
*/
|
|
||||||
private JsonWriter open(JsonScope empty, String openBracket) throws IOException {
|
|
||||||
beforeValue(true);
|
|
||||||
stack.add(empty);
|
|
||||||
out.write(openBracket);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the current scope by appending any necessary whitespace and the
|
|
||||||
* given bracket.
|
|
||||||
*/
|
|
||||||
private JsonWriter close(JsonScope empty, JsonScope nonempty, String closeBracket)
|
|
||||||
throws IOException {
|
|
||||||
JsonScope context = peek();
|
|
||||||
if (context != nonempty && context != empty) {
|
|
||||||
throw new IllegalStateException("Nesting problem: " + stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.remove(stack.size() - 1);
|
|
||||||
if (context == nonempty) {
|
|
||||||
newline();
|
|
||||||
}
|
|
||||||
out.write(closeBracket);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value on the top of the stack.
|
|
||||||
*/
|
|
||||||
private JsonScope peek() {
|
|
||||||
return stack.get(stack.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace the value on the top of the stack with the given value.
|
|
||||||
*/
|
|
||||||
private void replaceTop(JsonScope topOfStack) {
|
|
||||||
stack.set(stack.size() - 1, topOfStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes the property name.
|
|
||||||
*
|
|
||||||
* @param name the name of the forthcoming value. May not be null.
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter name(String name) throws IOException {
|
|
||||||
if (name == null) {
|
|
||||||
throw new NullPointerException("name == null");
|
|
||||||
}
|
|
||||||
beforeName();
|
|
||||||
string(name);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes {@code value}.
|
|
||||||
*
|
|
||||||
* @param value the literal string value, or null to encode a null literal.
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter value(String value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
return nullValue();
|
|
||||||
}
|
|
||||||
beforeValue(false);
|
|
||||||
string(value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes {@code null}.
|
|
||||||
*
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter nullValue() throws IOException {
|
|
||||||
beforeValue(false);
|
|
||||||
out.write("null");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes {@code value}.
|
|
||||||
*
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter value(boolean value) throws IOException {
|
|
||||||
beforeValue(false);
|
|
||||||
out.write(value ? "true" : "false");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes {@code value}.
|
|
||||||
*
|
|
||||||
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
|
|
||||||
* {@link Double#isInfinite() infinities}.
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter value(double value) throws IOException {
|
|
||||||
if (Double.isNaN(value) || Double.isInfinite(value)) {
|
|
||||||
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
|
|
||||||
}
|
|
||||||
beforeValue(false);
|
|
||||||
out.append(Double.toString(value));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes {@code value}.
|
|
||||||
*
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter value(long value) throws IOException {
|
|
||||||
beforeValue(false);
|
|
||||||
out.write(Long.toString(value));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes {@code value}.
|
|
||||||
*
|
|
||||||
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
|
|
||||||
* {@link Double#isInfinite() infinities}.
|
|
||||||
* @return this writer.
|
|
||||||
*/
|
|
||||||
public JsonWriter value(Number value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
return nullValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
String string = value.toString();
|
|
||||||
if (!lenient
|
|
||||||
&& (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
|
|
||||||
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
|
|
||||||
}
|
|
||||||
beforeValue(false);
|
|
||||||
out.append(string);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures all buffered data is written to the underlying {@link Writer}
|
|
||||||
* and flushes that writer.
|
|
||||||
*/
|
|
||||||
public void flush() throws IOException {
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flushes and closes this writer and the underlying {@link Writer}.
|
|
||||||
*
|
|
||||||
* @throws IOException if the JSON document is incomplete.
|
|
||||||
*/
|
|
||||||
public void close() throws IOException {
|
|
||||||
out.close();
|
|
||||||
|
|
||||||
if (peek() != JsonScope.NONEMPTY_DOCUMENT) {
|
|
||||||
throw new IOException("Incomplete document");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void string(String value) throws IOException {
|
|
||||||
out.write("\"");
|
|
||||||
for (int i = 0, length = value.length(); i < length; i++) {
|
|
||||||
char c = value.charAt(i);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* From RFC 4627, "All Unicode characters may be placed within the
|
|
||||||
* quotation marks except for the characters that must be escaped:
|
|
||||||
* quotation mark, reverse solidus, and the control characters
|
|
||||||
* (U+0000 through U+001F)."
|
|
||||||
*/
|
|
||||||
switch (c) {
|
|
||||||
case '"':
|
|
||||||
case '\\':
|
|
||||||
out.write('\\');
|
|
||||||
out.write(c);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\t':
|
|
||||||
out.write("\\t");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\b':
|
|
||||||
out.write("\\b");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\n':
|
|
||||||
out.write("\\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\r':
|
|
||||||
out.write("\\r");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\f':
|
|
||||||
out.write("\\f");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '<':
|
|
||||||
case '>':
|
|
||||||
case '&':
|
|
||||||
case '=':
|
|
||||||
case '\'':
|
|
||||||
if (htmlSafe) {
|
|
||||||
out.write(String.format("\\u%04x", (int) c));
|
|
||||||
} else {
|
|
||||||
out.write(c);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (c <= 0x1F) {
|
|
||||||
out.write(String.format("\\u%04x", (int) c));
|
|
||||||
} else {
|
|
||||||
out.write(c);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.write("\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void newline() throws IOException {
|
|
||||||
if (indent == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write("\n");
|
|
||||||
for (int i = 1; i < stack.size(); i++) {
|
|
||||||
out.write(indent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts any necessary separators and whitespace before a name. Also
|
|
||||||
* adjusts the stack to expect the name's value.
|
|
||||||
*/
|
|
||||||
private void beforeName() throws IOException {
|
|
||||||
JsonScope context = peek();
|
|
||||||
if (context == JsonScope.NONEMPTY_OBJECT) { // first in object
|
|
||||||
out.write(',');
|
|
||||||
} else if (context != JsonScope.EMPTY_OBJECT) { // not in an object!
|
|
||||||
throw new IllegalStateException("Nesting problem: " + stack);
|
|
||||||
}
|
|
||||||
newline();
|
|
||||||
replaceTop(JsonScope.DANGLING_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts any necessary separators and whitespace before a literal value,
|
|
||||||
* inline array, or inline object. Also adjusts the stack to expect either a
|
|
||||||
* closing bracket or another element.
|
|
||||||
*
|
|
||||||
* @param root true if the value is a new array or object, the two values
|
|
||||||
* permitted as top-level elements.
|
|
||||||
*/
|
|
||||||
private void beforeValue(boolean root) throws IOException {
|
|
||||||
switch (peek()) {
|
|
||||||
case EMPTY_DOCUMENT: // first in document
|
|
||||||
if (!lenient && !root) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"JSON must start with an array or an object.");
|
|
||||||
}
|
|
||||||
replaceTop(JsonScope.NONEMPTY_DOCUMENT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EMPTY_ARRAY: // first in array
|
|
||||||
replaceTop(JsonScope.NONEMPTY_ARRAY);
|
|
||||||
newline();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NONEMPTY_ARRAY: // another in array
|
|
||||||
out.append(',');
|
|
||||||
newline();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DANGLING_NAME: // value for name
|
|
||||||
out.append(separator);
|
|
||||||
replaceTop(JsonScope.NONEMPTY_OBJECT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NONEMPTY_DOCUMENT:
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"JSON must have only one top-level value.");
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Nesting problem: " + stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.mcteam.ancientgates.gson.stream;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when a reader encounters malformed JSON. Some syntax errors can be
|
|
||||||
* ignored by calling {@link JsonReader#setLenient(boolean)}.
|
|
||||||
*/
|
|
||||||
public final class MalformedJsonException extends IOException {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public MalformedJsonException(String msg) {
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MalformedJsonException(String msg, Throwable throwable) {
|
|
||||||
super(msg);
|
|
||||||
// Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException
|
|
||||||
// with a constructor with Throwable. This was done in Java 1.6
|
|
||||||
initCause(throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MalformedJsonException(Throwable throwable) {
|
|
||||||
// Using initCause() instead of calling super() because Java 1.5 didn't retrofit IOException
|
|
||||||
// with a constructor with Throwable. This was done in Java 1.6
|
|
||||||
initCause(throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.listeners;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.BlockFace;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class PluginBlockListener implements Listener
|
|
||||||
{
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL)
|
|
||||||
public void onBlockPhysics(BlockPhysicsEvent event)
|
|
||||||
{
|
|
||||||
if (event.isCancelled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (event.getBlock().getType() != Material.PORTAL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBlockInPortal(event.getBlock())) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBlockInPortal(Block block)
|
|
||||||
{
|
|
||||||
if (block.getRelative(BlockFace.UP).getType() == Material.AIR)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (block.getRelative(BlockFace.DOWN).getType() == Material.AIR)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( block.getRelative(BlockFace.NORTH).getType() != Material.AIR && block.getRelative(BlockFace.SOUTH).getType() != Material.AIR )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ( block.getRelative(BlockFace.WEST).getType() != Material.AIR && block.getRelative(BlockFace.EAST).getType() != Material.AIR )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.listeners;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.bukkit.Chunk;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.BlockFace;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
|
||||||
|
|
||||||
import org.mcteam.ancientgates.Conf;
|
|
||||||
import org.mcteam.ancientgates.Gate;
|
|
||||||
import org.mcteam.ancientgates.Plugin;
|
|
||||||
import org.mcteam.ancientgates.util.GeometryUtil;
|
|
||||||
|
|
||||||
|
|
||||||
public class PluginPlayerListener implements Listener
|
|
||||||
{
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.NORMAL)
|
|
||||||
public void onPlayerMove(PlayerMoveEvent event)
|
|
||||||
{
|
|
||||||
if (event.isCancelled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Block blockTo = event.getTo().getBlock();
|
|
||||||
Block blockToUp = blockTo.getRelative(BlockFace.UP);
|
|
||||||
|
|
||||||
|
|
||||||
// Check if player is standing inside a portal
|
|
||||||
if (blockTo.getType() != Material.PORTAL && blockToUp.getType() != Material.PORTAL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
// Ok so a player walks into a portal block
|
|
||||||
// Find the nearest gate!
|
|
||||||
Gate nearestGate = null;
|
|
||||||
Location playerLocation = event.getPlayer().getLocation();
|
|
||||||
//double shortestDistance = -1;
|
|
||||||
|
|
||||||
for (Gate gate : Gate.getAll())
|
|
||||||
{
|
|
||||||
if ( gate.getFrom() == null || gate.getTo() == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
|
||||||
if ( ! gate.getFrom().getWorld().equals(playerLocation.getWorld()))
|
|
||||||
continue; // We can only be close to gates in the same world
|
|
||||||
|
|
||||||
|
|
||||||
double distance = GeometryUtil.distanceBetweenLocations(playerLocation, gate.getFrom());
|
|
||||||
|
|
||||||
if (distance > Conf.getGateSearchRadius())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
|
||||||
Plugin.log(Level.ALL, "in gate search radius.");
|
|
||||||
for (Integer[] blockXYZ: gate.getGateBlocks())
|
|
||||||
{
|
|
||||||
if ( (blockTo.getX() == blockXYZ[0] || blockToUp.getX() == blockXYZ[0]) &&
|
|
||||||
(blockTo.getY() == blockXYZ[1] || blockToUp.getY() == blockXYZ[1]) &&
|
|
||||||
(blockTo.getZ() == blockXYZ[2] || blockToUp.getZ() == blockXYZ[2])
|
|
||||||
)
|
|
||||||
{
|
|
||||||
nearestGate = gate;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*if (shortestDistance == -1 || shortestDistance > distance) {
|
|
||||||
nearestGate = gate;
|
|
||||||
shortestDistance = distance;
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nearestGate != null)
|
|
||||||
{
|
|
||||||
checkChunkLoad(nearestGate.getTo().getBlock());
|
|
||||||
|
|
||||||
Float newYaw = nearestGate.getFrom().getYaw() - nearestGate.getTo().getYaw() + playerLocation.getYaw();
|
|
||||||
|
|
||||||
Location teleportToLocation = new Location( nearestGate.getTo().getWorld(),
|
|
||||||
nearestGate.getTo().getX(),
|
|
||||||
nearestGate.getTo().getY(),
|
|
||||||
nearestGate.getTo().getZ(),
|
|
||||||
newYaw, playerLocation.getPitch() );
|
|
||||||
|
|
||||||
event.getPlayer().teleport(teleportToLocation);
|
|
||||||
event.setTo(teleportToLocation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void checkChunkLoad(Block b)
|
|
||||||
{
|
|
||||||
World w = b.getWorld();
|
|
||||||
Chunk c = b.getChunk();
|
|
||||||
|
|
||||||
if ( ! w.isChunkLoaded(c) )
|
|
||||||
{
|
|
||||||
Plugin.log(Level.FINE, "Loading chunk: " + c.toString() + " on: " + w.toString());
|
|
||||||
w.loadChunk(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.util;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Harddisc related methods such as read and write.
|
|
||||||
*/
|
|
||||||
public class DiscUtil {
|
|
||||||
/**
|
|
||||||
* Convenience function for writing a string to a file.
|
|
||||||
*/
|
|
||||||
public static void write(File file, String content) throws IOException {
|
|
||||||
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), "UTF8"));
|
|
||||||
out.write(content);
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience function for reading a file as a string.
|
|
||||||
*/
|
|
||||||
public static String read(File file) throws IOException {
|
|
||||||
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
|
|
||||||
String ret = new String(new byte[0], "UTF-8");
|
|
||||||
|
|
||||||
String line;
|
|
||||||
while ((line = in.readLine()) != null) {
|
|
||||||
ret += line;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.util;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.BlockFace;
|
|
||||||
import org.mcteam.ancientgates.Conf;
|
|
||||||
import org.mcteam.ancientgates.Plugin;
|
|
||||||
|
|
||||||
public class FloodUtil {
|
|
||||||
private static final Set<BlockFace> exp1 = new HashSet<BlockFace>();
|
|
||||||
private static final Set<BlockFace> exp2 = new HashSet<BlockFace>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
exp1.add(BlockFace.UP);
|
|
||||||
exp1.add(BlockFace.DOWN);
|
|
||||||
exp1.add(BlockFace.EAST);
|
|
||||||
exp1.add(BlockFace.WEST);
|
|
||||||
|
|
||||||
exp2.add(BlockFace.UP);
|
|
||||||
exp2.add(BlockFace.DOWN);
|
|
||||||
exp2.add(BlockFace.NORTH);
|
|
||||||
exp2.add(BlockFace.SOUTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// For the same frame and location this set of blocks is deterministic
|
|
||||||
public static Set<Block> getGateFrameBlocks(Block block) {
|
|
||||||
Set<Block> blocks1 = getAirFloodBlocks(block, new HashSet<Block>(), exp1, Conf.getGateMaxArea());
|
|
||||||
Set<Block> blocks2 = getAirFloodBlocks(block, new HashSet<Block>(), exp2, Conf.getGateMaxArea());
|
|
||||||
|
|
||||||
if (blocks1 == null && blocks2 == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blocks1 == null) {
|
|
||||||
return blocks2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blocks2 == null) {
|
|
||||||
return blocks1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blocks1.size() > blocks2.size()) {
|
|
||||||
return blocks2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return blocks1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Set<Block> getAirFloodBlocks(Block startBlock, Set<Block> foundBlocks, Set<BlockFace> expandFaces, int limit)
|
|
||||||
{
|
|
||||||
if (foundBlocks == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (foundBlocks.size() > limit)
|
|
||||||
{
|
|
||||||
Plugin.log(Level.ALL, "exceeding gate size limit.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundBlocks.contains(startBlock))
|
|
||||||
return foundBlocks;
|
|
||||||
|
|
||||||
if (startBlock.getType() == Material.AIR || startBlock.getType() == Material.PORTAL)
|
|
||||||
{
|
|
||||||
// ... We found a block :D ...
|
|
||||||
foundBlocks.add(startBlock);
|
|
||||||
|
|
||||||
// ... And flood away !
|
|
||||||
for (BlockFace face : expandFaces)
|
|
||||||
{
|
|
||||||
Block potentialBlock = startBlock.getRelative(face);
|
|
||||||
foundBlocks = getAirFloodBlocks(potentialBlock, foundBlocks, expandFaces, limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return foundBlocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.util;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
|
||||||
|
|
||||||
public class GeometryUtil {
|
|
||||||
|
|
||||||
// How long between two locations?
|
|
||||||
public static double distanceBetweenLocations(Location location1, Location location2) {
|
|
||||||
double X = location1.getX() - location2.getX();
|
|
||||||
double Y = location1.getY() - location2.getY();
|
|
||||||
double Z = location1.getZ() - location2.getZ();
|
|
||||||
return Math.sqrt(X*X+Y*Y+Z*Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package org.mcteam.ancientgates.util;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.mcteam.ancientgates.Conf;
|
|
||||||
|
|
||||||
public class TextUtil {
|
|
||||||
public static String titleize(String str) {
|
|
||||||
String line = Conf.colorChrome+repeat("_", 60);
|
|
||||||
String center = ".[ " + Conf.colorSystem + str + Conf.colorChrome + " ].";
|
|
||||||
int pivot = line.length() / 2;
|
|
||||||
int eatLeft = center.length() / 2;
|
|
||||||
int eatRight = center.length() - eatLeft;
|
|
||||||
return line.substring(0, pivot - eatLeft) + center + line.substring(pivot + eatRight);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String repeat(String s, int times) {
|
|
||||||
if (times <= 0) return "";
|
|
||||||
else return s + repeat(s, times-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ArrayList<String> split(String str) {
|
|
||||||
return new ArrayList<String>(Arrays.asList(str.trim().split("\\s+")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String implode(List<String> list, String glue) {
|
|
||||||
String ret = "";
|
|
||||||
for (int i=0; i<list.size(); i++) {
|
|
||||||
if (i!=0) {
|
|
||||||
ret += glue;
|
|
||||||
}
|
|
||||||
ret += list.get(i);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
public static String implode(List<String> list) {
|
|
||||||
return implode(list, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getMaterialName(Material material) {
|
|
||||||
String ret = material.toString();
|
|
||||||
ret = ret.replace('_', ' ');
|
|
||||||
ret = ret.toLowerCase();
|
|
||||||
return ret.substring(0, 1).toUpperCase()+ret.substring(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
name: AncientGates
|
|
||||||
version: 1.0.1
|
|
||||||
main: org.mcteam.ancientgates.Plugin
|
|
||||||
commands:
|
|
||||||
gate:
|
|
||||||
description: All of the AncientGates commands
|
|
||||||
usage: See documentation.
|
|
||||||
Reference in New Issue
Block a user