Use MassiveXlib shaded artifact
This commit is contained in:
parent
1d02942085
commit
7babdf910c
5
pom.xml
5
pom.xml
@ -21,6 +21,11 @@
|
|||||||
|
|
||||||
<!-- Dependencies -->
|
<!-- Dependencies -->
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<!-- MassiveXlib -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.massivecraft.massivecore</groupId>
|
||||||
|
<artifactId>MassiveXlib</artifactId>
|
||||||
|
</dependency>
|
||||||
<!-- Spigot -->
|
<!-- Spigot -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
|
@ -1,350 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BSON.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.util.ClassMap;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes"})
|
|
||||||
public class BSON {
|
|
||||||
|
|
||||||
static final Logger LOGGER = Logger.getLogger( "org.bson.BSON" );
|
|
||||||
|
|
||||||
// ---- basics ----
|
|
||||||
|
|
||||||
public static final byte EOO = 0;
|
|
||||||
public static final byte NUMBER = 1;
|
|
||||||
public static final byte STRING = 2;
|
|
||||||
public static final byte OBJECT = 3;
|
|
||||||
public static final byte ARRAY = 4;
|
|
||||||
public static final byte BINARY = 5;
|
|
||||||
public static final byte UNDEFINED = 6;
|
|
||||||
public static final byte OID = 7;
|
|
||||||
public static final byte BOOLEAN = 8;
|
|
||||||
public static final byte DATE = 9;
|
|
||||||
public static final byte NULL = 10;
|
|
||||||
public static final byte REGEX = 11;
|
|
||||||
public static final byte REF = 12;
|
|
||||||
public static final byte CODE = 13;
|
|
||||||
public static final byte SYMBOL = 14;
|
|
||||||
public static final byte CODE_W_SCOPE = 15;
|
|
||||||
public static final byte NUMBER_INT = 16;
|
|
||||||
public static final byte TIMESTAMP = 17;
|
|
||||||
public static final byte NUMBER_LONG = 18;
|
|
||||||
|
|
||||||
public static final byte MINKEY = -1;
|
|
||||||
public static final byte MAXKEY = 127;
|
|
||||||
|
|
||||||
// --- binary types
|
|
||||||
/*
|
|
||||||
these are binary types
|
|
||||||
so the format would look like
|
|
||||||
<BINARY><name><BINARY_TYPE><...>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static final byte B_GENERAL = 0;
|
|
||||||
public static final byte B_FUNC = 1;
|
|
||||||
public static final byte B_BINARY = 2;
|
|
||||||
public static final byte B_UUID = 3;
|
|
||||||
|
|
||||||
// ---- regular expression handling ----
|
|
||||||
|
|
||||||
/** Converts a string of regular expression flags from the database in Java regular
|
|
||||||
* expression flags.
|
|
||||||
* @param flags flags from database
|
|
||||||
* @return the Java flags
|
|
||||||
*/
|
|
||||||
public static int regexFlags( String flags ){
|
|
||||||
int fint = 0;
|
|
||||||
if ( flags == null || flags.length() == 0 )
|
|
||||||
return fint;
|
|
||||||
|
|
||||||
flags = flags.toLowerCase();
|
|
||||||
|
|
||||||
for( int i=0; i<flags.length(); i++ ) {
|
|
||||||
RegexFlag flag = RegexFlag.getByCharacter( flags.charAt( i ) );
|
|
||||||
if( flag != null ) {
|
|
||||||
fint |= flag.javaFlag;
|
|
||||||
if( flag.unsupported != null )
|
|
||||||
_warnUnsupportedRegex( flag.unsupported );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException( "unrecognized flag ["+flags.charAt( i ) + "] " + (int)flags.charAt(i) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int regexFlag( char c ){
|
|
||||||
RegexFlag flag = RegexFlag.getByCharacter( c );
|
|
||||||
if ( flag == null )
|
|
||||||
throw new IllegalArgumentException( "unrecognized flag [" + c + "]" );
|
|
||||||
|
|
||||||
if ( flag.unsupported != null ){
|
|
||||||
_warnUnsupportedRegex( flag.unsupported );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return flag.javaFlag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Converts Java regular expression flags into a string of flags for the database
|
|
||||||
* @param flags Java flags
|
|
||||||
* @return the flags for the database
|
|
||||||
*/
|
|
||||||
public static String regexFlags( int flags ){
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
|
|
||||||
for( RegexFlag flag : RegexFlag.values() ) {
|
|
||||||
if( ( flags & flag.javaFlag ) > 0 ) {
|
|
||||||
buf.append( flag.flagChar );
|
|
||||||
flags -= flag.javaFlag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( flags > 0 )
|
|
||||||
throw new IllegalArgumentException( "some flags could not be recognized." );
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum RegexFlag {
|
|
||||||
CANON_EQ( Pattern.CANON_EQ, 'c', "Pattern.CANON_EQ" ),
|
|
||||||
UNIX_LINES(Pattern.UNIX_LINES, 'd', "Pattern.UNIX_LINES" ),
|
|
||||||
GLOBAL( GLOBAL_FLAG, 'g', null ),
|
|
||||||
CASE_INSENSITIVE( Pattern.CASE_INSENSITIVE, 'i', null ),
|
|
||||||
MULTILINE(Pattern.MULTILINE, 'm', null ),
|
|
||||||
DOTALL( Pattern.DOTALL, 's', "Pattern.DOTALL" ),
|
|
||||||
LITERAL( Pattern.LITERAL, 't', "Pattern.LITERAL" ),
|
|
||||||
UNICODE_CASE( Pattern.UNICODE_CASE, 'u', "Pattern.UNICODE_CASE" ),
|
|
||||||
COMMENTS( Pattern.COMMENTS, 'x', null );
|
|
||||||
|
|
||||||
private static final Map<Character, RegexFlag> byCharacter = new HashMap<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
for (RegexFlag flag : values()) {
|
|
||||||
byCharacter.put(flag.flagChar, flag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RegexFlag getByCharacter(char ch) {
|
|
||||||
return byCharacter.get(ch);
|
|
||||||
}
|
|
||||||
public final int javaFlag;
|
|
||||||
public final char flagChar;
|
|
||||||
public final String unsupported;
|
|
||||||
|
|
||||||
RegexFlag( int f, char ch, String u ) {
|
|
||||||
javaFlag = f;
|
|
||||||
flagChar = ch;
|
|
||||||
unsupported = u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void _warnUnsupportedRegex( String flag ) {
|
|
||||||
LOGGER.info( "flag " + flag + " not supported by db." );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int GLOBAL_FLAG = 256;
|
|
||||||
|
|
||||||
// --- (en|de)coding hooks -----
|
|
||||||
|
|
||||||
public static boolean hasDecodeHooks() { return _decodeHooks; }
|
|
||||||
|
|
||||||
public static void addEncodingHook( Class c , Transformer t ){
|
|
||||||
_encodeHooks = true;
|
|
||||||
List<Transformer> l = _encodingHooks.get( c );
|
|
||||||
if ( l == null ){
|
|
||||||
l = new CopyOnWriteArrayList<>();
|
|
||||||
_encodingHooks.put( c , l );
|
|
||||||
}
|
|
||||||
l.add( t );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addDecodingHook( Class c , Transformer t ){
|
|
||||||
_decodeHooks = true;
|
|
||||||
List<Transformer> l = _decodingHooks.get( c );
|
|
||||||
if ( l == null ){
|
|
||||||
l = new CopyOnWriteArrayList<>();
|
|
||||||
_decodingHooks.put( c , l );
|
|
||||||
}
|
|
||||||
l.add( t );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object applyEncodingHooks( Object o ){
|
|
||||||
if ( ! _anyHooks() )
|
|
||||||
return o;
|
|
||||||
|
|
||||||
if ( _encodingHooks.size() == 0 || o == null )
|
|
||||||
return o;
|
|
||||||
List<Transformer> l = _encodingHooks.get( o.getClass() );
|
|
||||||
if ( l != null )
|
|
||||||
for ( Transformer t : l )
|
|
||||||
o = t.transform( o );
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object applyDecodingHooks( Object o ){
|
|
||||||
if ( ! _anyHooks() || o == null )
|
|
||||||
return o;
|
|
||||||
|
|
||||||
List<Transformer> l = _decodingHooks.get( o.getClass() );
|
|
||||||
if ( l != null )
|
|
||||||
for ( Transformer t : l )
|
|
||||||
o = t.transform( o );
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the encoding hook(s) associated with the specified class
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static List<Transformer> getEncodingHooks( Class c ){
|
|
||||||
return _encodingHooks.get( c );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears *all* encoding hooks.
|
|
||||||
*/
|
|
||||||
public static void clearEncodingHooks(){
|
|
||||||
_encodeHooks = false;
|
|
||||||
_encodingHooks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all encoding hooks for a specific class.
|
|
||||||
*/
|
|
||||||
public static void removeEncodingHooks( Class c ){
|
|
||||||
_encodingHooks.remove( c );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a specific encoding hook for a specific class.
|
|
||||||
*/
|
|
||||||
public static void removeEncodingHook( Class c , Transformer t ){
|
|
||||||
getEncodingHooks( c ).remove( t );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the decoding hook(s) associated with the specific class
|
|
||||||
*/
|
|
||||||
public static List<Transformer> getDecodingHooks( Class c ){
|
|
||||||
return _decodingHooks.get( c );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears *all* decoding hooks.
|
|
||||||
*/
|
|
||||||
public static void clearDecodingHooks(){
|
|
||||||
_decodeHooks = false;
|
|
||||||
_decodingHooks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all decoding hooks for a specific class.
|
|
||||||
*/
|
|
||||||
public static void removeDecodingHooks( Class c ){
|
|
||||||
_decodingHooks.remove( c );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a specific encoding hook for a specific class.
|
|
||||||
*/
|
|
||||||
public static void removeDecodingHook( Class c , Transformer t ){
|
|
||||||
getDecodingHooks( c ).remove( t );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void clearAllHooks(){
|
|
||||||
clearEncodingHooks();
|
|
||||||
clearDecodingHooks();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if any encoding or decoding hooks are loaded.
|
|
||||||
*/
|
|
||||||
private static boolean _anyHooks(){
|
|
||||||
return _encodeHooks || _decodeHooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean _encodeHooks = false;
|
|
||||||
private static boolean _decodeHooks = false;
|
|
||||||
static ClassMap<List<Transformer>> _encodingHooks =
|
|
||||||
new ClassMap<>();
|
|
||||||
|
|
||||||
static ClassMap<List<Transformer>> _decodingHooks =
|
|
||||||
new ClassMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link Charset#forName(String)} to create UTF-8 charset.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
static protected Charset _utf8 = Charset.forName( "UTF-8" );
|
|
||||||
|
|
||||||
// ----- static encode/decode -----
|
|
||||||
|
|
||||||
public static byte[] encode( BSONObject o ){
|
|
||||||
BSONEncoder e = _staticEncoder.get();
|
|
||||||
try {
|
|
||||||
return e.encode( o );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
e.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BSONObject decode( byte[] b ){
|
|
||||||
BSONDecoder d = _staticDecoder.get();
|
|
||||||
return d.readObject( b );
|
|
||||||
}
|
|
||||||
|
|
||||||
static ThreadLocal<BSONEncoder> _staticEncoder = new ThreadLocal<BSONEncoder>(){
|
|
||||||
protected BSONEncoder initialValue(){
|
|
||||||
return new BasicBSONEncoder();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static ThreadLocal<BSONDecoder> _staticDecoder = new ThreadLocal<BSONDecoder>(){
|
|
||||||
protected BSONDecoder initialValue(){
|
|
||||||
return new BasicBSONDecoder();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- coercing ---
|
|
||||||
|
|
||||||
public static int toInt( Object o ){
|
|
||||||
if ( o == null )
|
|
||||||
throw new NullPointerException( "can't be null" );
|
|
||||||
|
|
||||||
if ( o instanceof Number )
|
|
||||||
return ((Number)o).intValue();
|
|
||||||
|
|
||||||
if ( o instanceof Boolean )
|
|
||||||
return ((Boolean)o) ? 1 : 0;
|
|
||||||
|
|
||||||
throw new IllegalArgumentException( "can't convert: " + o.getClass().getName() + " to int" );
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BSONCallback.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
|
|
||||||
public interface BSONCallback {
|
|
||||||
|
|
||||||
void objectStart();
|
|
||||||
void objectStart(String name);
|
|
||||||
void objectStart(boolean array);
|
|
||||||
Object objectDone();
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
Object get();
|
|
||||||
BSONCallback createBSONCallback();
|
|
||||||
|
|
||||||
void arrayStart();
|
|
||||||
void arrayStart(String name);
|
|
||||||
Object arrayDone();
|
|
||||||
|
|
||||||
void gotNull( String name );
|
|
||||||
void gotUndefined( String name );
|
|
||||||
void gotMinKey( String name );
|
|
||||||
void gotMaxKey( String name );
|
|
||||||
|
|
||||||
void gotBoolean( String name , boolean v );
|
|
||||||
void gotDouble( String name , double v );
|
|
||||||
void gotInt( String name , int v );
|
|
||||||
void gotLong( String name , long v );
|
|
||||||
|
|
||||||
void gotDate( String name , long millis );
|
|
||||||
void gotString( String name , String v );
|
|
||||||
void gotSymbol( String name , String v );
|
|
||||||
void gotRegex( String name , String pattern , String flags );
|
|
||||||
|
|
||||||
void gotTimestamp( String name , int time , int inc );
|
|
||||||
void gotObjectId( String name , ObjectId id );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked when {@link com.massivecraft.massivecore.xlib.bson.BSONDecoder} encountered a DBPointer(0x0c) type field in a byte sequence.
|
|
||||||
*
|
|
||||||
* @param name the name of the field
|
|
||||||
* @param ns the namespace to which reference is pointing to
|
|
||||||
* @param id the if of the object to which reference is pointing to
|
|
||||||
*/
|
|
||||||
void gotDBRef(String name, String ns, ObjectId id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
void gotBinaryArray( String name , byte[] data );
|
|
||||||
void gotBinary( String name , byte type , byte[] data );
|
|
||||||
/**
|
|
||||||
* subtype 3
|
|
||||||
*/
|
|
||||||
void gotUUID( String name , long part1, long part2);
|
|
||||||
|
|
||||||
void gotCode( String name , String code );
|
|
||||||
void gotCodeWScope( String name , String code , Object scope );
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BSONDecoder.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public interface BSONDecoder {
|
|
||||||
|
|
||||||
BSONObject readObject(byte[] b);
|
|
||||||
|
|
||||||
BSONObject readObject(InputStream in) throws IOException;
|
|
||||||
|
|
||||||
int decode(byte[] b, BSONCallback callback);
|
|
||||||
|
|
||||||
int decode(InputStream in, BSONCallback callback) throws IOException;
|
|
||||||
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.OutputBuffer;
|
|
||||||
|
|
||||||
|
|
||||||
public interface BSONEncoder {
|
|
||||||
byte[] encode(BSONObject o);
|
|
||||||
|
|
||||||
int putObject(BSONObject o);
|
|
||||||
|
|
||||||
void done();
|
|
||||||
|
|
||||||
void set( OutputBuffer out );
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A general runtime exception raised in BSON processing.
|
|
||||||
*/
|
|
||||||
public class BSONException extends RuntimeException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -4415279469780082174L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param msg The error message.
|
|
||||||
*/
|
|
||||||
public BSONException( final String msg ) {
|
|
||||||
super( msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param errorCode The error code.
|
|
||||||
* @param msg The error message.
|
|
||||||
*/
|
|
||||||
public BSONException( final int errorCode, final String msg ) {
|
|
||||||
super( msg );
|
|
||||||
_errorCode = errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param msg The error message.
|
|
||||||
* @param t The throwable cause.
|
|
||||||
*/
|
|
||||||
public BSONException( final String msg , final Throwable t ) {
|
|
||||||
super( msg, t );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param errorCode The error code.
|
|
||||||
* @param msg The error message.
|
|
||||||
* @param t The throwable cause.
|
|
||||||
*/
|
|
||||||
public BSONException( final int errorCode, final String msg, final Throwable t ) {
|
|
||||||
super( msg, t );
|
|
||||||
_errorCode = errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the error code.
|
|
||||||
* @return The error code.
|
|
||||||
*/
|
|
||||||
public Integer getErrorCode() { return _errorCode; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the error code is set (i.e., not null).
|
|
||||||
*/
|
|
||||||
public boolean hasErrorCode() { return (_errorCode != null); }
|
|
||||||
|
|
||||||
private Integer _errorCode = null;
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author antoine
|
|
||||||
*
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class BSONLazyDecoder {
|
|
||||||
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BSONObject.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A key-value map that can be saved to the database.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"rawtypes"})
|
|
||||||
public interface BSONObject {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a name/value pair in this object.
|
|
||||||
* @param key Name to set
|
|
||||||
* @param v Corresponding value
|
|
||||||
* @return <tt>v</tt>
|
|
||||||
*/
|
|
||||||
Object put(String key, Object v);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets all key/value pairs from an object into this object
|
|
||||||
* @param o the object
|
|
||||||
*/
|
|
||||||
void putAll(BSONObject o);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets all key/value pairs from a map into this object
|
|
||||||
* @param m the map
|
|
||||||
*/
|
|
||||||
void putAll(Map m);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a field from this object by a given name.
|
|
||||||
* @param key The name of the field fetch
|
|
||||||
* @return The field, if found
|
|
||||||
*/
|
|
||||||
Object get(String key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a map representing this BSONObject.
|
|
||||||
* @return the map
|
|
||||||
*/
|
|
||||||
Map toMap();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a field with a given name from this object.
|
|
||||||
* @param key The name of the field to remove
|
|
||||||
* @return The value removed from this object
|
|
||||||
*/
|
|
||||||
Object removeField(String key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated
|
|
||||||
* @param s
|
|
||||||
* @return True if the key is present
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
boolean containsKey(String s);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this object contains a field with the given name.
|
|
||||||
* @param s Field name for which to check
|
|
||||||
* @return True if the field is present
|
|
||||||
*/
|
|
||||||
boolean containsField(String s);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this object's fields' names
|
|
||||||
* @return The names of the fields in this object
|
|
||||||
*/
|
|
||||||
Set<String> keySet();
|
|
||||||
}
|
|
||||||
|
|
@ -1,216 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BasicBSONCallback.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.BSONTimestamp;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.BasicBSONList;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.Binary;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.Code;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.CodeWScope;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.MaxKey;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.MinKey;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class BasicBSONCallback implements BSONCallback {
|
|
||||||
|
|
||||||
public BasicBSONCallback(){
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONObject create(){
|
|
||||||
return new BasicBSONObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected BSONObject createList() {
|
|
||||||
return new BasicBSONList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONCallback createBSONCallback(){
|
|
||||||
return new BasicBSONCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONObject create( boolean array , List<String> path ){
|
|
||||||
if ( array )
|
|
||||||
return createList();
|
|
||||||
return create();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart(){
|
|
||||||
if ( _stack.size() > 0 )
|
|
||||||
throw new IllegalStateException( "something is wrong" );
|
|
||||||
|
|
||||||
objectStart(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart(boolean array){
|
|
||||||
_root = create(array, null);
|
|
||||||
_stack.add( (BSONObject)_root );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart(String name){
|
|
||||||
objectStart( false , name );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart(boolean array, String name){
|
|
||||||
_nameStack.addLast( name );
|
|
||||||
final BSONObject o = create( array , _nameStack );
|
|
||||||
_stack.getLast().put( name , o);
|
|
||||||
_stack.addLast( o );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object objectDone(){
|
|
||||||
final BSONObject o =_stack.removeLast();
|
|
||||||
if ( _nameStack.size() > 0 )
|
|
||||||
_nameStack.removeLast();
|
|
||||||
else if ( _stack.size() > 0 )
|
|
||||||
throw new IllegalStateException( "something is wrong" );
|
|
||||||
|
|
||||||
return !BSON.hasDecodeHooks() ? o : (BSONObject)BSON.applyDecodingHooks(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void arrayStart(){
|
|
||||||
objectStart( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void arrayStart(String name){
|
|
||||||
objectStart( true , name );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object arrayDone(){
|
|
||||||
return objectDone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotNull( String name ){
|
|
||||||
cur().put( name , null );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotUndefined( String name ) { }
|
|
||||||
|
|
||||||
public void gotMinKey( String name ){
|
|
||||||
cur().put( name , new MinKey() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotMaxKey( String name ){
|
|
||||||
cur().put( name , new MaxKey() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotBoolean( String name , boolean v ){
|
|
||||||
_put( name , v );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotDouble( final String name , final double v ){
|
|
||||||
_put( name , v );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotInt( final String name , final int v ){
|
|
||||||
_put( name , v );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotLong( final String name , final long v ){
|
|
||||||
_put( name , v );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotDate( String name , long millis ){
|
|
||||||
_put( name , new Date( millis ) );
|
|
||||||
}
|
|
||||||
public void gotRegex( String name , String pattern , String flags ){
|
|
||||||
_put( name , Pattern.compile( pattern , BSON.regexFlags( flags ) ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotString( final String name , final String v ){
|
|
||||||
_put( name , v );
|
|
||||||
}
|
|
||||||
public void gotSymbol( String name , String v ){
|
|
||||||
_put( name , v );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotTimestamp( String name , int time , int inc ){
|
|
||||||
_put( name , new BSONTimestamp( time , inc ) );
|
|
||||||
}
|
|
||||||
public void gotObjectId( String name , ObjectId id ){
|
|
||||||
_put( name , id );
|
|
||||||
}
|
|
||||||
public void gotDBRef( String name , String ns , ObjectId id ){
|
|
||||||
_put( name , new BasicBSONObject( "$ns" , ns ).append( "$id" , id ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void gotBinaryArray( String name , byte[] data ){
|
|
||||||
gotBinary( name, BSON.B_GENERAL, data );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotBinary( String name , byte type , byte[] data ){
|
|
||||||
if( type == BSON.B_GENERAL || type == BSON.B_BINARY )
|
|
||||||
_put( name , data );
|
|
||||||
else
|
|
||||||
_put( name , new Binary( type , data ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotUUID( String name , long part1, long part2){
|
|
||||||
_put( name , new UUID(part1, part2) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotCode( String name , String code ){
|
|
||||||
_put( name , new Code( code ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotCodeWScope( String name , String code , Object scope ){
|
|
||||||
_put( name , new CodeWScope( code, (BSONObject)scope ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void _put( final String name , final Object o ){
|
|
||||||
cur().put( name , !BSON.hasDecodeHooks() ? o : BSON.applyDecodingHooks( o ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected BSONObject cur(){
|
|
||||||
return _stack.getLast();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String curName(){
|
|
||||||
return (!_nameStack.isEmpty()) ? _nameStack.getLast() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(){
|
|
||||||
return _root;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setRoot(Object o) {
|
|
||||||
_root = o;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isStackEmpty() {
|
|
||||||
return _stack.size() < 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset(){
|
|
||||||
_root = null;
|
|
||||||
_stack.clear();
|
|
||||||
_nameStack.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object _root;
|
|
||||||
private final LinkedList<BSONObject> _stack = new LinkedList<>();
|
|
||||||
private final LinkedList<String> _nameStack = new LinkedList<>();
|
|
||||||
}
|
|
@ -1,639 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.PoolOutputBuffer;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.ARRAY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.BINARY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.BOOLEAN;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_BINARY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_GENERAL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_UUID;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.CODE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.CODE_W_SCOPE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.DATE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.EOO;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.MAXKEY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.MINKEY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NULL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER_INT;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER_LONG;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.OBJECT;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.OID;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.REF;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.REGEX;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.STRING;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.SYMBOL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.TIMESTAMP;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.UNDEFINED;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic implementation of BSONDecoder interface that creates BasicBSONObject instances.
|
|
||||||
*
|
|
||||||
* <h3>Migration instructions</h3>
|
|
||||||
* In driver versions before <b>2.12</b> {@code BasicBSONDecoder} exposed several protected members to its subclasses:
|
|
||||||
* <br/><br/>
|
|
||||||
* <b>Fields:</b>
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code protected BSONInput _in}</li>
|
|
||||||
* <li>{@code protected BSONCallback _callback}</li>
|
|
||||||
* <li>{@code protected int _len}</li>
|
|
||||||
* <li>{@code protected int _pos}</li>
|
|
||||||
*
|
|
||||||
* </ul>
|
|
||||||
* <br/>
|
|
||||||
* <b>Methods:</b>
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code protected void _binary(String)}</li>
|
|
||||||
* </ul>
|
|
||||||
* <br/>
|
|
||||||
* <b>Nested Classes:</b>
|
|
||||||
* <ul>
|
|
||||||
* <li>{@code protected class BSONInput}</li>
|
|
||||||
* </ul>
|
|
||||||
* <br/>
|
|
||||||
*
|
|
||||||
*<h4>Solution 1: Custom {@link BSONCallback} implementation</h4>
|
|
||||||
* With callbacks you can handle the process of creating objects from bytes in BSON format.
|
|
||||||
* <p>
|
|
||||||
* For example to get away from overriging <b>{@code BasicBSONDecoder._binary(String)}</b>
|
|
||||||
* you can use the following piece of code:
|
|
||||||
* </p>
|
|
||||||
* <pre>
|
|
||||||
* <code style="background:#eee;display:inline-block;padding:10px">public class CustomBSONCallback extends BasicBSONCallback {
|
|
||||||
*
|
|
||||||
* public void gotBinary(String name, byte type, byte[] data) {
|
|
||||||
* _put(name,toHex(data));
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* private static String toHex(byte[] bytes) {...}
|
|
||||||
*}
|
|
||||||
*</code></pre>
|
|
||||||
*
|
|
||||||
* This solution covers majority of the cases.
|
|
||||||
*
|
|
||||||
* <h4>Solution 2: Custom {@link BSONDecoder} implementation</h4>
|
|
||||||
* If you need to customize byte-level decoding at the lowest layer you have to provide you own
|
|
||||||
* implementation of the {@link BSONDecoder} interface.
|
|
||||||
* <br/>
|
|
||||||
* Please check <a href="http://bsonspec.org/">http://bsonspec.org/</a> for more information.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class BasicBSONDecoder implements BSONDecoder {
|
|
||||||
public BSONObject readObject( byte[] b ){
|
|
||||||
try {
|
|
||||||
return readObject( new ByteArrayInputStream( b ) );
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ){
|
|
||||||
throw new BSONException( "should be impossible" , ioe );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONObject readObject( InputStream in )
|
|
||||||
throws IOException {
|
|
||||||
BasicBSONCallback c = new BasicBSONCallback();
|
|
||||||
decode( in , c );
|
|
||||||
return (BSONObject)c.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int decode( byte[] b , BSONCallback callback ){
|
|
||||||
try {
|
|
||||||
return _decode( new BSONInput( new ByteArrayInputStream(b) ) , callback );
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ){
|
|
||||||
throw new BSONException( "should be impossible" , ioe );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int decode( InputStream in , BSONCallback callback )
|
|
||||||
throws IOException {
|
|
||||||
return _decode( new BSONInput( in ) , callback );
|
|
||||||
}
|
|
||||||
|
|
||||||
private int _decode( BSONInput in , BSONCallback callback )
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
if ( _in != null || _callback != null )
|
|
||||||
throw new IllegalStateException( "not ready" );
|
|
||||||
|
|
||||||
_in = in;
|
|
||||||
_callback = callback;
|
|
||||||
|
|
||||||
if ( in.numRead() != 0 )
|
|
||||||
throw new IllegalArgumentException( "i'm confused" );
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
final int len = _in.readInt();
|
|
||||||
|
|
||||||
_in.setMax(len);
|
|
||||||
|
|
||||||
_callback.objectStart();
|
|
||||||
while ( decodeElement() );
|
|
||||||
_callback.objectDone();
|
|
||||||
|
|
||||||
if ( _in.numRead() != len )
|
|
||||||
throw new IllegalArgumentException( "bad data. lengths don't match read:" + _in.numRead() + " != len:" + len );
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
_in = null;
|
|
||||||
_callback = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int decode( boolean first )
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
final int start = _in.numRead();
|
|
||||||
|
|
||||||
final int len = _in.readInt();
|
|
||||||
if ( first )
|
|
||||||
_in.setMax(len);
|
|
||||||
|
|
||||||
_callback.objectStart();
|
|
||||||
while ( decodeElement() );
|
|
||||||
_callback.objectDone();
|
|
||||||
|
|
||||||
final int read = _in.numRead() - start;
|
|
||||||
|
|
||||||
if ( read != len ){
|
|
||||||
//throw new IllegalArgumentException( "bad data. lengths don't match " + read + " != " + len );
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean decodeElement()
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
final byte type = _in.read();
|
|
||||||
|
|
||||||
if ( type == EOO )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
String name = _in.readCStr();
|
|
||||||
|
|
||||||
switch ( type ){
|
|
||||||
case NULL:
|
|
||||||
_callback.gotNull( name );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UNDEFINED:
|
|
||||||
_callback.gotUndefined( name );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BOOLEAN:
|
|
||||||
_callback.gotBoolean( name , _in.read() > 0 );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NUMBER:
|
|
||||||
_callback.gotDouble( name , _in.readDouble() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NUMBER_INT:
|
|
||||||
_callback.gotInt( name , _in.readInt() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NUMBER_LONG:
|
|
||||||
_callback.gotLong( name , _in.readLong() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SYMBOL:
|
|
||||||
_callback.gotSymbol( name , _in.readUTF8String() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STRING:
|
|
||||||
_callback.gotString(name, _in.readUTF8String() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OID:
|
|
||||||
// OID is stored as big endian
|
|
||||||
_callback.gotObjectId( name , new ObjectId( _in.readIntBE() , _in.readIntBE() , _in.readIntBE() ) );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REF:
|
|
||||||
_in.readInt(); // length of ctring that follows
|
|
||||||
String ns = _in.readCStr();
|
|
||||||
ObjectId theOID = new ObjectId( _in.readInt() , _in.readInt() , _in.readInt() );
|
|
||||||
_callback.gotDBRef( name , ns , theOID );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DATE:
|
|
||||||
_callback.gotDate( name , _in.readLong() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REGEX:
|
|
||||||
_callback.gotRegex( name , _in.readCStr() , _in.readCStr() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BINARY:
|
|
||||||
_binary( name );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CODE:
|
|
||||||
_callback.gotCode( name , _in.readUTF8String() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CODE_W_SCOPE:
|
|
||||||
_in.readInt();
|
|
||||||
_callback.gotCodeWScope( name , _in.readUTF8String() , _readBasicObject() );
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ARRAY:
|
|
||||||
_in.readInt(); // total size - we don't care....
|
|
||||||
|
|
||||||
_callback.arrayStart( name );
|
|
||||||
while ( decodeElement() );
|
|
||||||
_callback.arrayDone();
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case OBJECT:
|
|
||||||
_in.readInt(); // total size - we don't care....
|
|
||||||
|
|
||||||
_callback.objectStart( name );
|
|
||||||
while ( decodeElement() );
|
|
||||||
_callback.objectDone();
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMESTAMP:
|
|
||||||
int i = _in.readInt();
|
|
||||||
int time = _in.readInt();
|
|
||||||
_callback.gotTimestamp( name , time , i );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MINKEY:
|
|
||||||
_callback.gotMinKey( name );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MAXKEY:
|
|
||||||
_callback.gotMaxKey( name );
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException( "BSONDecoder doesn't understand type : " + type + " name: " + name );
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param name the field name
|
|
||||||
* @throws IOException
|
|
||||||
*
|
|
||||||
* @deprecated This method should not be a part of API.
|
|
||||||
* Please see the class-level documentation for a migration instructions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected void _binary( final String name )
|
|
||||||
throws IOException {
|
|
||||||
final int totalLen = _in.readInt();
|
|
||||||
final byte bType = _in.read();
|
|
||||||
|
|
||||||
switch ( bType ){
|
|
||||||
case B_GENERAL: {
|
|
||||||
final byte[] data = new byte[totalLen];
|
|
||||||
_in.fill( data );
|
|
||||||
_callback.gotBinary( name, bType, data );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case B_BINARY:
|
|
||||||
final int len = _in.readInt();
|
|
||||||
if ( len + 4 != totalLen )
|
|
||||||
throw new IllegalArgumentException( "bad data size subtype 2 len: " + len + " totalLen: " + totalLen );
|
|
||||||
|
|
||||||
final byte [] data = new byte[len];
|
|
||||||
_in.fill( data );
|
|
||||||
_callback.gotBinary( name , bType , data );
|
|
||||||
return;
|
|
||||||
case B_UUID:
|
|
||||||
if ( totalLen != 16 )
|
|
||||||
throw new IllegalArgumentException( "bad data size subtype 3 len: " + totalLen + " != 16");
|
|
||||||
|
|
||||||
final long part1 = _in.readLong();
|
|
||||||
final long part2 = _in.readLong();
|
|
||||||
_callback.gotUUID(name, part1, part2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte [] data = new byte[totalLen];
|
|
||||||
_in.fill( data );
|
|
||||||
|
|
||||||
_callback.gotBinary( name , bType , data );
|
|
||||||
}
|
|
||||||
|
|
||||||
Object _readBasicObject()
|
|
||||||
throws IOException {
|
|
||||||
_in.readInt();
|
|
||||||
|
|
||||||
final BSONCallback save = _callback;
|
|
||||||
final BSONCallback _basic = _callback.createBSONCallback();
|
|
||||||
_callback = _basic;
|
|
||||||
_basic.reset();
|
|
||||||
_basic.objectStart(false);
|
|
||||||
|
|
||||||
while( decodeElement() );
|
|
||||||
_callback = save;
|
|
||||||
return _basic.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This class should not be a part of API.
|
|
||||||
* Please see the class-level documentation for a migration instructions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected class BSONInput {
|
|
||||||
|
|
||||||
public BSONInput(final InputStream in){
|
|
||||||
_raw = in;
|
|
||||||
_read = 0;
|
|
||||||
|
|
||||||
_pos = 0;
|
|
||||||
_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ensure that there are num bytes to read
|
|
||||||
* _pos is where to start reading from
|
|
||||||
* @return where to start reading from
|
|
||||||
*/
|
|
||||||
protected int _need( final int num )
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
//System.out.println( "p: " + _pos + " l: " + _len + " want: " + num );
|
|
||||||
|
|
||||||
if ( _len - _pos >= num ){
|
|
||||||
final int ret = _pos;
|
|
||||||
_pos += num;
|
|
||||||
_read += num;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( num >= _inputBuffer.length )
|
|
||||||
throw new IllegalArgumentException( "you can't need that much" );
|
|
||||||
|
|
||||||
final int remaining = _len - _pos;
|
|
||||||
if ( _pos > 0 ){
|
|
||||||
System.arraycopy( _inputBuffer , _pos , _inputBuffer , 0 , remaining );
|
|
||||||
|
|
||||||
_pos = 0;
|
|
||||||
_len = remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read as much as possible into buffer
|
|
||||||
int maxToRead = Math.min( _max - _read - remaining , _inputBuffer.length - _len );
|
|
||||||
while ( maxToRead > 0 ){
|
|
||||||
int x = _raw.read( _inputBuffer , _len , maxToRead);
|
|
||||||
if ( x <= 0 )
|
|
||||||
throw new IOException( "unexpected EOF" );
|
|
||||||
maxToRead -= x;
|
|
||||||
_len += x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret = _pos;
|
|
||||||
_pos += num;
|
|
||||||
_read += num;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int readInt()
|
|
||||||
throws IOException {
|
|
||||||
return com.massivecraft.massivecore.xlib.bson.io.Bits.readInt( _inputBuffer , _need(4) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public int readIntBE()
|
|
||||||
throws IOException {
|
|
||||||
return com.massivecraft.massivecore.xlib.bson.io.Bits.readIntBE( _inputBuffer , _need(4) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public long readLong()
|
|
||||||
throws IOException {
|
|
||||||
return com.massivecraft.massivecore.xlib.bson.io.Bits.readLong( _inputBuffer , _need(8) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public double readDouble()
|
|
||||||
throws IOException {
|
|
||||||
return Double.longBitsToDouble( readLong() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte read()
|
|
||||||
throws IOException {
|
|
||||||
if ( _pos < _len ){
|
|
||||||
++_read;
|
|
||||||
return _inputBuffer[_pos++];
|
|
||||||
}
|
|
||||||
return _inputBuffer[_need(1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( byte b[] )
|
|
||||||
throws IOException {
|
|
||||||
fill( b , b.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( byte b[] , int len )
|
|
||||||
throws IOException {
|
|
||||||
// first use what we have
|
|
||||||
final int have = _len - _pos;
|
|
||||||
final int tocopy = Math.min( len , have );
|
|
||||||
System.arraycopy( _inputBuffer , _pos , b , 0 , tocopy );
|
|
||||||
|
|
||||||
_pos += tocopy;
|
|
||||||
_read += tocopy;
|
|
||||||
|
|
||||||
len -= tocopy;
|
|
||||||
|
|
||||||
int off = tocopy;
|
|
||||||
while ( len > 0 ){
|
|
||||||
final int x = _raw.read( b , off , len );
|
|
||||||
if (x <= 0)
|
|
||||||
throw new IOException( "unexpected EOF" );
|
|
||||||
_read += x;
|
|
||||||
off += x;
|
|
||||||
len -= x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean _isAscii( byte b ){
|
|
||||||
return b >=0 && b <= 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String readCStr() throws IOException {
|
|
||||||
|
|
||||||
boolean isAscii = true;
|
|
||||||
|
|
||||||
// short circuit 1 byte strings
|
|
||||||
_random[0] = read();
|
|
||||||
if (_random[0] == 0) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
_random[1] = read();
|
|
||||||
if (_random[1] == 0) {
|
|
||||||
final String out = ONE_BYTE_STRINGS[_random[0]];
|
|
||||||
return (out != null) ? out : new String(_random, 0, 1, DEFAULT_ENCODING);
|
|
||||||
}
|
|
||||||
|
|
||||||
_stringBuffer.reset();
|
|
||||||
_stringBuffer.write(_random, 0, 2);
|
|
||||||
|
|
||||||
isAscii = _isAscii(_random[0]) && _isAscii(_random[1]);
|
|
||||||
|
|
||||||
byte b;
|
|
||||||
while ((b = read()) != 0) {
|
|
||||||
_stringBuffer.write( b );
|
|
||||||
isAscii = isAscii && _isAscii( b );
|
|
||||||
}
|
|
||||||
|
|
||||||
String out = null;
|
|
||||||
if ( isAscii ){
|
|
||||||
out = _stringBuffer.asAscii();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
out = _stringBuffer.asString( DEFAULT_ENCODING );
|
|
||||||
}
|
|
||||||
catch ( UnsupportedOperationException e ){
|
|
||||||
throw new BSONException( "impossible" , e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_stringBuffer.reset();
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String readUTF8String()
|
|
||||||
throws IOException {
|
|
||||||
final int size = readInt();
|
|
||||||
// this is just protection in case it's corrupted, to avoid huge strings
|
|
||||||
if ( size <= 0 || size > MAX_STRING )
|
|
||||||
throw new BSONException( "bad string size: " + size );
|
|
||||||
|
|
||||||
if ( size < _inputBuffer.length / 2 ){
|
|
||||||
if ( size == 1 ){
|
|
||||||
read();
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String( _inputBuffer , _need(size) , size - 1 , DEFAULT_ENCODING );
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte [] b = size < _random.length ? _random : new byte[size];
|
|
||||||
|
|
||||||
fill( b , size );
|
|
||||||
|
|
||||||
try {
|
|
||||||
return new String( b , 0 , size - 1 , DEFAULT_ENCODING );
|
|
||||||
}
|
|
||||||
catch ( java.io.UnsupportedEncodingException uee ){
|
|
||||||
throw new BSONException( "impossible" , uee );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int numRead() {
|
|
||||||
return _read;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPos() {
|
|
||||||
return _pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMax() {
|
|
||||||
return _max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMax(int _max) {
|
|
||||||
this._max = _max;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _read;
|
|
||||||
final InputStream _raw;
|
|
||||||
|
|
||||||
int _max = 4; // max number of total bytes allowed to ready
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This field should not be a part of API.
|
|
||||||
* Please see the class-level documentation for a migration instructions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected BSONInput _in;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This field should not be a part of API.
|
|
||||||
* Please see the class-level documentation for a migration instructions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected BSONCallback _callback;
|
|
||||||
|
|
||||||
private byte [] _random = new byte[1024]; // has to be used within a single function
|
|
||||||
private byte [] _inputBuffer = new byte[1024];
|
|
||||||
|
|
||||||
private PoolOutputBuffer _stringBuffer = new PoolOutputBuffer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This field should not be a part of API.
|
|
||||||
* Please see the class-level documentation for a migration instructions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected int _pos; // current offset into _inputBuffer
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This field should not be a part of API.
|
|
||||||
* Please see the class-level documentation for a migration instructions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected int _len; // length of valid data in _inputBuffer
|
|
||||||
|
|
||||||
private static final int MAX_STRING = ( 32 * 1024 * 1024 );
|
|
||||||
|
|
||||||
private static final String DEFAULT_ENCODING = "UTF-8";
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static final boolean _isAscii( final byte b ){
|
|
||||||
return b >=0 && b <= 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
static final String[] ONE_BYTE_STRINGS = new String[128];
|
|
||||||
static void _fillRange( byte min, byte max ){
|
|
||||||
while ( min < max ){
|
|
||||||
String s = "";
|
|
||||||
s += (char)min;
|
|
||||||
ONE_BYTE_STRINGS[(int)min] = s;
|
|
||||||
min++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static {
|
|
||||||
_fillRange( (byte)'0' , (byte)'9' );
|
|
||||||
_fillRange( (byte)'a' , (byte)'z' );
|
|
||||||
_fillRange( (byte)'A' , (byte)'Z' );
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,537 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BSONEncoder.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.BasicOutputBuffer;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.OutputBuffer;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.BSONTimestamp;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.Binary;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.Code;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.CodeWScope;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.MaxKey;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.MinKey;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.Symbol;
|
|
||||||
import com.massivecraft.massivecore.xlib.mongodb.DBRefBase;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.nio.Buffer;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.ARRAY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.BINARY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.BOOLEAN;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_BINARY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_GENERAL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_UUID;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.CODE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.CODE_W_SCOPE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.DATE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.EOO;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.MAXKEY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.MINKEY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NULL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER_INT;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER_LONG;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.OBJECT;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.OID;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.REGEX;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.STRING;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.SYMBOL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.TIMESTAMP;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.UNDEFINED;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.regexFlags;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this is meant to be pooled or cached
|
|
||||||
* there is some per instance memory for string conversion, etc...
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes", "deprecation", "unused"})
|
|
||||||
public class BasicBSONEncoder implements BSONEncoder {
|
|
||||||
|
|
||||||
static final boolean DEBUG = false;
|
|
||||||
|
|
||||||
public BasicBSONEncoder(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] encode( BSONObject o ){
|
|
||||||
BasicOutputBuffer buf = new BasicOutputBuffer();
|
|
||||||
set( buf );
|
|
||||||
putObject( o );
|
|
||||||
done();
|
|
||||||
return buf.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set( OutputBuffer out ){
|
|
||||||
if ( _buf != null )
|
|
||||||
throw new IllegalStateException( "in the middle of something" );
|
|
||||||
|
|
||||||
_buf = out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the buffer this encoder is writing to.
|
|
||||||
*
|
|
||||||
* @return the output buffer
|
|
||||||
*/
|
|
||||||
protected OutputBuffer getOutputBuffer() {
|
|
||||||
return _buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void done(){
|
|
||||||
_buf = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if object was handled
|
|
||||||
*
|
|
||||||
* @deprecated Override {@link #putSpecial(String, Object)} if you need to you need to handle custom types.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected boolean handleSpecialObjects( String name , BSONObject o ){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean putSpecial( String name , Object o ){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Encodes a <code>BSONObject</code>.
|
|
||||||
* This is for the higher level api calls
|
|
||||||
* @param o the object to encode
|
|
||||||
* @return the number of characters in the encoding
|
|
||||||
*/
|
|
||||||
public int putObject( BSONObject o ){
|
|
||||||
return putObject( null , o );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this is really for embedded objects
|
|
||||||
*/
|
|
||||||
protected int putObject( String name , BSONObject o ){
|
|
||||||
|
|
||||||
if ( o == null )
|
|
||||||
throw new NullPointerException( "can't save a null object" );
|
|
||||||
|
|
||||||
if ( DEBUG ) System.out.println( "putObject : " + name + " [" + o.getClass() + "]" + " # keys " + o.keySet().size() );
|
|
||||||
|
|
||||||
final int start = _buf.getPosition();
|
|
||||||
|
|
||||||
byte myType = OBJECT;
|
|
||||||
if ( o instanceof List )
|
|
||||||
myType = ARRAY;
|
|
||||||
|
|
||||||
if ( handleSpecialObjects( name , o ) )
|
|
||||||
return _buf.getPosition() - start;
|
|
||||||
|
|
||||||
if ( name != null ){
|
|
||||||
_put( myType , name );
|
|
||||||
}
|
|
||||||
|
|
||||||
final int sizePos = _buf.getPosition();
|
|
||||||
_buf.writeInt( 0 ); // leaving space for this. set it at the end
|
|
||||||
|
|
||||||
List transientFields = null;
|
|
||||||
boolean rewriteID = myType == OBJECT && name == null;
|
|
||||||
|
|
||||||
|
|
||||||
if ( myType == OBJECT ) {
|
|
||||||
if ( rewriteID && o.containsField( "_id" ) )
|
|
||||||
_putObjectField( "_id" , o.get( "_id" ) );
|
|
||||||
|
|
||||||
{
|
|
||||||
Object temp = o.get( "_transientFields" );
|
|
||||||
if ( temp instanceof List )
|
|
||||||
transientFields = (List)temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: reduce repeated code below.
|
|
||||||
if ( o instanceof Map ){
|
|
||||||
for ( Entry<String, Object> e : ((Map<String, Object>)o).entrySet() ){
|
|
||||||
|
|
||||||
if ( rewriteID && e.getKey().equals( "_id" ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( transientFields != null && transientFields.contains( e.getKey() ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_putObjectField( e.getKey() , e.getValue() );
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for ( String s : o.keySet() ){
|
|
||||||
|
|
||||||
if ( rewriteID && s.equals( "_id" ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( transientFields != null && transientFields.contains( s ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Object val = o.get( s );
|
|
||||||
|
|
||||||
_putObjectField( s , val );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_buf.write( EOO );
|
|
||||||
|
|
||||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
|
||||||
return _buf.getPosition() - start;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void _putObjectField( String name , Object val ){
|
|
||||||
|
|
||||||
if ( name.equals( "_transientFields" ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( DEBUG ) System.out.println( "\t put thing : " + name );
|
|
||||||
|
|
||||||
if ( name.contains( "\0" ) )
|
|
||||||
throw new IllegalArgumentException( "Document field names can't have a NULL character. (Bad Key: '" + name + "')" );
|
|
||||||
|
|
||||||
if ( name.equals( "$where") && val instanceof String ){
|
|
||||||
_put( CODE , name );
|
|
||||||
_putValueString( val.toString() );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
val = BSON.applyEncodingHooks( val );
|
|
||||||
|
|
||||||
if ( val == null )
|
|
||||||
putNull(name);
|
|
||||||
else if ( val instanceof Date )
|
|
||||||
putDate( name , (Date)val );
|
|
||||||
else if ( val instanceof Number )
|
|
||||||
putNumber(name, (Number)val );
|
|
||||||
else if ( val instanceof Character )
|
|
||||||
putString(name, val.toString() );
|
|
||||||
else if ( val instanceof String )
|
|
||||||
putString(name, val.toString() );
|
|
||||||
else if ( val instanceof ObjectId )
|
|
||||||
putObjectId(name, (ObjectId)val );
|
|
||||||
else if ( val instanceof BSONObject )
|
|
||||||
putObject(name, (BSONObject)val );
|
|
||||||
else if ( val instanceof Boolean )
|
|
||||||
putBoolean(name, (Boolean)val );
|
|
||||||
else if ( val instanceof Pattern )
|
|
||||||
putPattern(name, (Pattern)val );
|
|
||||||
else if ( val instanceof Map )
|
|
||||||
putMap( name , (Map)val );
|
|
||||||
else if ( val instanceof Iterable)
|
|
||||||
putIterable( name , (Iterable)val );
|
|
||||||
else if ( val instanceof byte[] )
|
|
||||||
putBinary( name , (byte[])val );
|
|
||||||
else if ( val instanceof Binary )
|
|
||||||
putBinary( name , (Binary)val );
|
|
||||||
else if ( val instanceof UUID )
|
|
||||||
putUUID( name , (UUID)val );
|
|
||||||
else if ( val.getClass().isArray() )
|
|
||||||
putArray( name , val );
|
|
||||||
|
|
||||||
else if (val instanceof Symbol) {
|
|
||||||
putSymbol(name, (Symbol) val);
|
|
||||||
}
|
|
||||||
else if (val instanceof BSONTimestamp) {
|
|
||||||
putTimestamp( name , (BSONTimestamp)val );
|
|
||||||
}
|
|
||||||
else if (val instanceof CodeWScope) {
|
|
||||||
putCodeWScope( name , (CodeWScope)val );
|
|
||||||
}
|
|
||||||
else if (val instanceof Code) {
|
|
||||||
putCode( name , (Code)val );
|
|
||||||
}
|
|
||||||
else if (val instanceof DBRefBase) {
|
|
||||||
BSONObject temp = new BasicBSONObject();
|
|
||||||
temp.put("$ref", ((DBRefBase)val).getRef());
|
|
||||||
temp.put("$id", ((DBRefBase)val).getId());
|
|
||||||
putObject( name, temp );
|
|
||||||
}
|
|
||||||
else if ( val instanceof MinKey )
|
|
||||||
putMinKey( name );
|
|
||||||
else if ( val instanceof MaxKey )
|
|
||||||
putMaxKey( name );
|
|
||||||
else if ( putSpecial( name , val ) ){
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException( "can't serialize " + val.getClass() );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putArray( String name , Object array ) {
|
|
||||||
_put( ARRAY , name );
|
|
||||||
final int sizePos = _buf.getPosition();
|
|
||||||
_buf.writeInt( 0 );
|
|
||||||
|
|
||||||
int size = Array.getLength(array);
|
|
||||||
for ( int i = 0; i < size; i++ )
|
|
||||||
_putObjectField( String.valueOf( i ) , Array.get( array, i ) );
|
|
||||||
|
|
||||||
_buf.write( EOO );
|
|
||||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putIterable( String name , Iterable l ){
|
|
||||||
_put( ARRAY , name );
|
|
||||||
final int sizePos = _buf.getPosition();
|
|
||||||
_buf.writeInt( 0 );
|
|
||||||
|
|
||||||
int i=0;
|
|
||||||
for ( Object obj: l ) {
|
|
||||||
_putObjectField( String.valueOf( i ) , obj );
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_buf.write( EOO );
|
|
||||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putMap( String name , Map m ){
|
|
||||||
_put( OBJECT , name );
|
|
||||||
final int sizePos = _buf.getPosition();
|
|
||||||
_buf.writeInt( 0 );
|
|
||||||
|
|
||||||
for ( Map.Entry entry : (Set<Map.Entry>)m.entrySet() )
|
|
||||||
_putObjectField( entry.getKey().toString() , entry.getValue() );
|
|
||||||
|
|
||||||
_buf.write( EOO );
|
|
||||||
_buf.writeInt( sizePos , _buf.getPosition() - sizePos );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void putNull( String name ){
|
|
||||||
_put( NULL , name );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putUndefined(String name){
|
|
||||||
_put(UNDEFINED, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putTimestamp(String name, BSONTimestamp ts ){
|
|
||||||
_put( TIMESTAMP , name );
|
|
||||||
_buf.writeInt( ts.getInc() );
|
|
||||||
_buf.writeInt( ts.getTime() );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putCodeWScope( String name , CodeWScope code ){
|
|
||||||
_put( CODE_W_SCOPE , name );
|
|
||||||
int temp = _buf.getPosition();
|
|
||||||
_buf.writeInt( 0 );
|
|
||||||
_putValueString( code.getCode() );
|
|
||||||
putObject( code.getScope() );
|
|
||||||
_buf.writeInt( temp , _buf.getPosition() - temp );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putCode( String name , Code code ){
|
|
||||||
_put( CODE , name );
|
|
||||||
int temp = _buf.getPosition();
|
|
||||||
_putValueString( code.getCode() );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putBoolean( String name , Boolean b ){
|
|
||||||
_put( BOOLEAN , name );
|
|
||||||
_buf.write( b ? (byte)0x1 : (byte)0x0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putDate( String name , Date d ){
|
|
||||||
_put( DATE , name );
|
|
||||||
_buf.writeLong( d.getTime() );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putNumber( String name , Number n ){
|
|
||||||
if ( n instanceof Integer ||
|
|
||||||
n instanceof Short ||
|
|
||||||
n instanceof Byte ||
|
|
||||||
n instanceof AtomicInteger ){
|
|
||||||
_put( NUMBER_INT , name );
|
|
||||||
_buf.writeInt( n.intValue() );
|
|
||||||
}
|
|
||||||
else if ( n instanceof Long || n instanceof AtomicLong ) {
|
|
||||||
_put( NUMBER_LONG , name );
|
|
||||||
_buf.writeLong( n.longValue() );
|
|
||||||
}
|
|
||||||
else if ( n instanceof Float || n instanceof Double ) {
|
|
||||||
_put( NUMBER , name );
|
|
||||||
_buf.writeDouble( n.doubleValue() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException( "can't serialize " + n.getClass() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putBinary( String name , byte[] data ){
|
|
||||||
putBinary( name, B_GENERAL, data );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putBinary( String name , Binary val ){
|
|
||||||
putBinary( name, val.getType(), val.getData() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putBinary( String name , int type , byte[] data ){
|
|
||||||
_put( BINARY , name );
|
|
||||||
int totalLen = data.length;
|
|
||||||
|
|
||||||
if (type == B_BINARY)
|
|
||||||
totalLen += 4;
|
|
||||||
|
|
||||||
_buf.writeInt( totalLen );
|
|
||||||
_buf.write( type );
|
|
||||||
if (type == B_BINARY)
|
|
||||||
_buf.writeInt( totalLen -4 );
|
|
||||||
int before = _buf.getPosition();
|
|
||||||
_buf.write( data );
|
|
||||||
int after = _buf.getPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putUUID( String name , UUID val ){
|
|
||||||
_put( BINARY , name );
|
|
||||||
_buf.writeInt( 16 );
|
|
||||||
_buf.write( B_UUID );
|
|
||||||
_buf.writeLong( val.getMostSignificantBits());
|
|
||||||
_buf.writeLong( val.getLeastSignificantBits());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putSymbol( String name , Symbol s ){
|
|
||||||
_putString(name, s.getSymbol(), SYMBOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putString(String name, String s) {
|
|
||||||
_putString(name, s, STRING);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _putString( String name , String s, byte type ){
|
|
||||||
_put( type , name );
|
|
||||||
_putValueString( s );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void putObjectId( String name , ObjectId oid ){
|
|
||||||
_put( OID , name );
|
|
||||||
// according to spec, values should be stored big endian
|
|
||||||
_buf.writeIntBE( oid._time() );
|
|
||||||
_buf.writeIntBE( oid._machine() );
|
|
||||||
_buf.writeIntBE( oid._inc() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putPattern( String name, Pattern p ) {
|
|
||||||
_put( REGEX , name );
|
|
||||||
_buf.writeCString( p.pattern() );
|
|
||||||
_buf.writeCString( regexFlags( p.flags() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putMinKey( String name ) {
|
|
||||||
_put( MINKEY , name );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putMaxKey( String name ) {
|
|
||||||
_put( MAXKEY , name );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes the type and key.
|
|
||||||
*
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
* Access buffer directly via {@link #getOutputBuffer()} if you need to change how BSON is written.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected void _put(byte type, String name) {
|
|
||||||
_buf.write(type);
|
|
||||||
_buf.writeCString(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
* Access buffer directly via {@link #getOutputBuffer()} if you need to change how BSON is written.
|
|
||||||
* Otherwise override {@link #putString(String, String)}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected void _putValueString( String s ){
|
|
||||||
_buf.writeString(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _reset( Buffer b ){
|
|
||||||
b.position(0);
|
|
||||||
b.limit(b.capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* puts as utf-8 string
|
|
||||||
*
|
|
||||||
* @deprecated Replaced by {@code getOutputBuffer().writeCString(String)}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected int _put( String str ){
|
|
||||||
return _buf.writeCString(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes integer to underlying buffer.
|
|
||||||
*
|
|
||||||
* @param x the integer number
|
|
||||||
* @deprecated Replaced by {@code getOutputBuffer().writeInt(int)}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void writeInt( int x ){
|
|
||||||
_buf.writeInt( x );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes long to underlying buffer.
|
|
||||||
*
|
|
||||||
* @param x the long number
|
|
||||||
* @deprecated Replaced by {@code getOutputBuffer().writeLong(long)}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void writeLong( long x ){
|
|
||||||
_buf.writeLong(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes C string (null-terminated string) to underlying buffer.
|
|
||||||
*
|
|
||||||
* @param s the string
|
|
||||||
* @deprecated Replaced by {@code getOutputBuffer().writeCString(String)}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void writeCString( String s ){
|
|
||||||
_buf.writeCString(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Replaced by {@link #getOutputBuffer()}.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected OutputBuffer _buf;
|
|
||||||
|
|
||||||
}
|
|
@ -1,399 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BasicBSONObject.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
// BSON
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.BasicBSONList;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
import com.massivecraft.massivecore.xlib.mongodb.util.JSONSerializers;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
|
|
||||||
// Java
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple implementation of <code>DBObject</code>.
|
|
||||||
* A <code>DBObject</code> can be created as follows, using this class:
|
|
||||||
* <blockquote><pre>
|
|
||||||
* DBObject obj = new BasicBSONObject();
|
|
||||||
* obj.put( "foo", "bar" );
|
|
||||||
* </pre></blockquote>
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes", "unused"})
|
|
||||||
public class BasicBSONObject extends LinkedHashMap<String,Object> implements BSONObject {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -4415279469780082174L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty object.
|
|
||||||
*/
|
|
||||||
public BasicBSONObject(){
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicBSONObject(int size){
|
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience CTOR
|
|
||||||
* @param key key under which to store
|
|
||||||
* @param value value to stor
|
|
||||||
*/
|
|
||||||
public BasicBSONObject(String key, Object value){
|
|
||||||
put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a DBObject from a map.
|
|
||||||
* @param m map to convert
|
|
||||||
*/
|
|
||||||
public BasicBSONObject(Map m) {
|
|
||||||
super(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a DBObject to a map.
|
|
||||||
* @return the DBObject
|
|
||||||
*/
|
|
||||||
public Map toMap() {
|
|
||||||
return new LinkedHashMap<>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Deletes a field from this object.
|
|
||||||
* @param key the field name to remove
|
|
||||||
* @return the object removed
|
|
||||||
*/
|
|
||||||
public Object removeField( String key ){
|
|
||||||
return remove( key );
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks if this object contains a given field
|
|
||||||
* @param field field name
|
|
||||||
* @return if the field exists
|
|
||||||
*/
|
|
||||||
public boolean containsField( String field ){
|
|
||||||
return super.containsKey(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public boolean containsKey( String key ){
|
|
||||||
return containsField(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a value from this object
|
|
||||||
* @param key field name
|
|
||||||
* @return the value
|
|
||||||
*/
|
|
||||||
public Object get( String key ){
|
|
||||||
return super.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the value of a field as an <code>int</code>.
|
|
||||||
* @param key the field to look for
|
|
||||||
* @return the field value (or default)
|
|
||||||
*/
|
|
||||||
public int getInt( String key ){
|
|
||||||
Object o = get(key);
|
|
||||||
if ( o == null )
|
|
||||||
throw new NullPointerException( "no value for: " + key );
|
|
||||||
|
|
||||||
return BSON.toInt(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the value of a field as an <code>int</code>.
|
|
||||||
* @param key the field to look for
|
|
||||||
* @param def the default to return
|
|
||||||
* @return the field value (or default)
|
|
||||||
*/
|
|
||||||
public int getInt( String key , int def ){
|
|
||||||
Object foo = get( key );
|
|
||||||
if ( foo == null )
|
|
||||||
return def;
|
|
||||||
|
|
||||||
return BSON.toInt(foo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of a field as a <code>long</code>.
|
|
||||||
*
|
|
||||||
* @param key the field to return
|
|
||||||
* @return the field value
|
|
||||||
*/
|
|
||||||
public long getLong( String key){
|
|
||||||
Object foo = get( key );
|
|
||||||
return ((Number)foo).longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of a field as an <code>long</code>.
|
|
||||||
* @param key the field to look for
|
|
||||||
* @param def the default to return
|
|
||||||
* @return the field value (or default)
|
|
||||||
*/
|
|
||||||
public long getLong( String key , long def ) {
|
|
||||||
Object foo = get( key );
|
|
||||||
if ( foo == null )
|
|
||||||
return def;
|
|
||||||
|
|
||||||
return ((Number)foo).longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of a field as a <code>double</code>.
|
|
||||||
*
|
|
||||||
* @param key the field to return
|
|
||||||
* @return the field value
|
|
||||||
*/
|
|
||||||
public double getDouble( String key){
|
|
||||||
Object foo = get( key );
|
|
||||||
return ((Number)foo).doubleValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of a field as an <code>double</code>.
|
|
||||||
* @param key the field to look for
|
|
||||||
* @param def the default to return
|
|
||||||
* @return the field value (or default)
|
|
||||||
*/
|
|
||||||
public double getDouble( String key , double def ) {
|
|
||||||
Object foo = get( key );
|
|
||||||
if ( foo == null )
|
|
||||||
return def;
|
|
||||||
|
|
||||||
return ((Number)foo).doubleValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the value of a field as a string
|
|
||||||
* @param key the field to look up
|
|
||||||
* @return the value of the field, converted to a string
|
|
||||||
*/
|
|
||||||
public String getString( String key ){
|
|
||||||
Object foo = get( key );
|
|
||||||
if ( foo == null )
|
|
||||||
return null;
|
|
||||||
return foo.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of a field as a string
|
|
||||||
* @param key the field to look up
|
|
||||||
* @param def the default to return
|
|
||||||
* @return the value of the field, converted to a string
|
|
||||||
*/
|
|
||||||
public String getString( String key, final String def ) {
|
|
||||||
Object foo = get( key );
|
|
||||||
if ( foo == null )
|
|
||||||
return def;
|
|
||||||
|
|
||||||
return foo.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the value of a field as a boolean.
|
|
||||||
* @param key the field to look up
|
|
||||||
* @return the value of the field, or false if field does not exist
|
|
||||||
*/
|
|
||||||
public boolean getBoolean( String key ){
|
|
||||||
return getBoolean(key, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the value of a field as a boolean
|
|
||||||
* @param key the field to look up
|
|
||||||
* @param def the default value in case the field is not found
|
|
||||||
* @return the value of the field, converted to a string
|
|
||||||
*/
|
|
||||||
public boolean getBoolean( String key , boolean def ){
|
|
||||||
Object foo = get( key );
|
|
||||||
if ( foo == null )
|
|
||||||
return def;
|
|
||||||
if ( foo instanceof Number )
|
|
||||||
return ((Number)foo).intValue() > 0;
|
|
||||||
if ( foo instanceof Boolean )
|
|
||||||
return ((Boolean)foo).booleanValue();
|
|
||||||
throw new IllegalArgumentException( "can't coerce to bool:" + foo.getClass() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the object id or null if not set.
|
|
||||||
* @param field The field to return
|
|
||||||
* @return The field object value or null if not found (or if null :-^).
|
|
||||||
*/
|
|
||||||
public ObjectId getObjectId( final String field ) {
|
|
||||||
return (ObjectId) get( field );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the object id or def if not set.
|
|
||||||
* @param field The field to return
|
|
||||||
* @param def the default value in case the field is not found
|
|
||||||
* @return The field object value or def if not set.
|
|
||||||
*/
|
|
||||||
public ObjectId getObjectId( final String field, final ObjectId def ) {
|
|
||||||
final Object foo = get( field );
|
|
||||||
return (foo != null) ? (ObjectId)foo : def;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the date or null if not set.
|
|
||||||
* @param field The field to return
|
|
||||||
* @return The field object value or null if not found.
|
|
||||||
*/
|
|
||||||
public Date getDate( final String field ) {
|
|
||||||
return (Date) get( field );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the date or def if not set.
|
|
||||||
* @param field The field to return
|
|
||||||
* @param def the default value in case the field is not found
|
|
||||||
* @return The field object value or def if not set.
|
|
||||||
*/
|
|
||||||
public Date getDate( final String field, final Date def ) {
|
|
||||||
final Object foo = get( field );
|
|
||||||
return (foo != null) ? (Date)foo : def;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a key/value pair to this object
|
|
||||||
* @param key the field name
|
|
||||||
* @param val the field value
|
|
||||||
* @return the <code>val</code> parameter
|
|
||||||
*/
|
|
||||||
public Object put( String key , Object val ){
|
|
||||||
return super.put( key , val );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll( Map m ){
|
|
||||||
for ( Map.Entry entry : (Set<Map.Entry>)m.entrySet() ){
|
|
||||||
put( entry.getKey().toString() , entry.getValue() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll( BSONObject o ){
|
|
||||||
for ( String k : o.keySet() ){
|
|
||||||
put( k , o.get( k ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a key/value pair to this object
|
|
||||||
* @param key the field name
|
|
||||||
* @param val the field value
|
|
||||||
* @return <code>this</code>
|
|
||||||
*/
|
|
||||||
public BasicBSONObject append( String key , Object val ){
|
|
||||||
put( key , val );
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a JSON serialization of this object
|
|
||||||
* @return JSON serialization
|
|
||||||
*/
|
|
||||||
public String toString(){
|
|
||||||
return JSONSerializers.getStrict().serialize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two documents according to their serialized form, ignoring the order of keys.
|
|
||||||
*
|
|
||||||
* @param o the document to compare to, which must be an instance of {@link com.massivecraft.massivecore.xlib.bson.BSONObject}.
|
|
||||||
* @return true if the documents have the same serialized form, ignoring key order.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals( Object o ) {
|
|
||||||
if (o == this) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! (o instanceof BSONObject)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BSONObject other = (BSONObject) o;
|
|
||||||
|
|
||||||
if (!keySet().equals(other.keySet())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Arrays.equals(canonicalizeBSONObject(this).encode(), canonicalizeBSONObject(other).encode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(canonicalizeBSONObject(this).encode());
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] encode() {
|
|
||||||
return new BasicBSONEncoder().encode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private BSONObject decode(final byte[] encodedBytes) {
|
|
||||||
return new BasicBSONDecoder().readObject(encodedBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a copy of "from", but with keys ordered alphabetically
|
|
||||||
private static Object canonicalize(final Object from) {
|
|
||||||
if (from instanceof BSONObject && !(from instanceof BasicBSONList)) {
|
|
||||||
return canonicalizeBSONObject((BSONObject) from);
|
|
||||||
} else if (from instanceof List) {
|
|
||||||
return canonicalizeList((List<Object>) from);
|
|
||||||
} else if (from instanceof Map) {
|
|
||||||
return canonicalizeMap((Map<String, Object>) from);
|
|
||||||
} else {
|
|
||||||
return from;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, Object> canonicalizeMap(final Map<String, Object> from) {
|
|
||||||
Map<String, Object> canonicalized = new LinkedHashMap<>(from.size());
|
|
||||||
TreeSet<String> keysInOrder = new TreeSet<>(from.keySet());
|
|
||||||
for (String key : keysInOrder) {
|
|
||||||
Object val = from.get(key);
|
|
||||||
canonicalized.put(key, canonicalize(val));
|
|
||||||
}
|
|
||||||
return canonicalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BasicBSONObject canonicalizeBSONObject(final BSONObject from) {
|
|
||||||
BasicBSONObject canonicalized = new BasicBSONObject();
|
|
||||||
TreeSet<String> keysInOrder = new TreeSet<>(from.keySet());
|
|
||||||
for (String key : keysInOrder) {
|
|
||||||
Object val = from.get(key);
|
|
||||||
canonicalized.put(key, canonicalize(val));
|
|
||||||
}
|
|
||||||
return canonicalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List canonicalizeList(final List<Object> list) {
|
|
||||||
List<Object> canonicalized = new ArrayList<>(list.size());
|
|
||||||
for (Object cur : list) {
|
|
||||||
canonicalized.add(canonicalize(cur));
|
|
||||||
}
|
|
||||||
return canonicalized;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
|
|
||||||
public class EmptyBSONCallback implements BSONCallback {
|
|
||||||
|
|
||||||
public void objectStart(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart( String name ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart( boolean array ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object objectDone(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONCallback createBSONCallback(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void arrayStart(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void arrayStart( String name ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object arrayDone(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotNull( String name ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotUndefined( String name ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotMinKey( String name ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotMaxKey( String name ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotBoolean( String name , boolean v ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotDouble( String name , double v ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotInt( String name , int v ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotLong( String name , long v ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotDate( String name , long millis ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotString( String name , String v ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotSymbol( String name , String v ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotRegex( String name , String pattern , String flags ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotTimestamp( String name , int time , int inc ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotObjectId( String name , ObjectId id ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotDBRef( String name , String ns , ObjectId id ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void gotBinaryArray( String name , byte[] data ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotUUID( String name , long part1 , long part2 ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotCode( String name , String code ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotCodeWScope( String name , String code , Object scope ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotBinary( String name , byte type , byte[] data ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.BSONByteBuffer;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author brendan
|
|
||||||
* @author scotthernandez
|
|
||||||
*
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class KeyCachingLazyBSONObject extends LazyBSONObject {
|
|
||||||
|
|
||||||
public KeyCachingLazyBSONObject(byte[] data , LazyBSONCallback cbk) { super( data , cbk ); }
|
|
||||||
public KeyCachingLazyBSONObject(byte[] data , int offset , LazyBSONCallback cbk) { super( data , offset , cbk ); }
|
|
||||||
public KeyCachingLazyBSONObject( BSONByteBuffer buffer, LazyBSONCallback callback ){ super( buffer, callback ); }
|
|
||||||
public KeyCachingLazyBSONObject( BSONByteBuffer buffer, int offset, LazyBSONCallback callback ){ super( buffer, offset, callback ); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object get( String key ) {
|
|
||||||
ensureFieldList();
|
|
||||||
return super.get( key );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsField( String s ) {
|
|
||||||
ensureFieldList();
|
|
||||||
if (! fieldIndex.containsKey( s ) )
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return super.containsField( s );
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized private void ensureFieldList() {
|
|
||||||
//only run once
|
|
||||||
if (fieldIndex == null) return;
|
|
||||||
try {
|
|
||||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
|
||||||
|
|
||||||
while ( !isElementEmpty( offset ) ){
|
|
||||||
int fieldSize = sizeCString( offset );
|
|
||||||
int elementSize = getElementBSONSize( offset++ );
|
|
||||||
String name = _input.getCString( offset );
|
|
||||||
ElementRecord _t_record = new ElementRecord( name, offset );
|
|
||||||
fieldIndex.put( name, _t_record );
|
|
||||||
offset += ( fieldSize + elementSize );
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
fieldIndex = new HashMap<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private HashMap<String, ElementRecord> fieldIndex = new HashMap<>();
|
|
||||||
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
import com.massivecraft.massivecore.xlib.mongodb.LazyDBObject;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"rawtypes", "unused"})
|
|
||||||
public class LazyBSONCallback extends EmptyBSONCallback {
|
|
||||||
|
|
||||||
public void objectStart(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart( String name ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void objectStart( boolean array ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object objectDone(){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset(){
|
|
||||||
_root = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get(){
|
|
||||||
return _root;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gotBinary( String name, byte type, byte[] data ){
|
|
||||||
setRootObject( createObject( data, 0 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void setRootObject( Object root ){
|
|
||||||
_root = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object createObject( byte[] data, int offset ){
|
|
||||||
return new LazyDBObject( data, offset, this );
|
|
||||||
}
|
|
||||||
|
|
||||||
public List createArray( byte[] data, int offset ){
|
|
||||||
return new LazyBSONList( data, offset, this );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object createDBRef( String ns, ObjectId id ){
|
|
||||||
return new BasicBSONObject( "$ns", ns ).append( "$id", id );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* public Object createObject(InputStream input, int offset) {
|
|
||||||
try {
|
|
||||||
return new LazyBSONObject(input, offset, this);
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
private Object _root;
|
|
||||||
private static final Logger log = Logger.getLogger( "org.bson.LazyBSONCallback" );
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.Bits;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* implementation of BSONDecoder that creates LazyBSONObject instances
|
|
||||||
*/
|
|
||||||
public class LazyBSONDecoder implements BSONDecoder {
|
|
||||||
static final Logger LOG = Logger.getLogger( LazyBSONDecoder.class.getName() );
|
|
||||||
|
|
||||||
public BSONObject readObject(byte[] b) {
|
|
||||||
try {
|
|
||||||
return readObject( new ByteArrayInputStream( b ) );
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ){
|
|
||||||
throw new BSONException( "should be impossible" , ioe );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONObject readObject(InputStream in) throws IOException {
|
|
||||||
BSONCallback c = new LazyBSONCallback();
|
|
||||||
decode( in , c );
|
|
||||||
return (BSONObject)c.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int decode(byte[] b, BSONCallback callback) {
|
|
||||||
try {
|
|
||||||
return decode( new ByteArrayInputStream( b ), callback );
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ) {
|
|
||||||
throw new BSONException( "should be impossible" , ioe );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int decode(InputStream in, BSONCallback callback) throws IOException {
|
|
||||||
byte[] objSizeBuffer = new byte[BYTES_IN_INTEGER];
|
|
||||||
Bits.readFully(in, objSizeBuffer, 0, BYTES_IN_INTEGER);
|
|
||||||
int objSize = Bits.readInt(objSizeBuffer);
|
|
||||||
byte[] data = new byte[objSize];
|
|
||||||
System.arraycopy(objSizeBuffer, 0, data, 0, BYTES_IN_INTEGER);
|
|
||||||
|
|
||||||
Bits.readFully(in, data, BYTES_IN_INTEGER, objSize - BYTES_IN_INTEGER);
|
|
||||||
|
|
||||||
// note that we are handing off ownership of the data byte array to the callback
|
|
||||||
callback.gotBinary(null, (byte) 0, data);
|
|
||||||
return objSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int BYTES_IN_INTEGER = 4;
|
|
||||||
}
|
|
@ -1,196 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.BSONByteBuffer;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ListIterator;
|
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "deprecation"})
|
|
||||||
public class LazyBSONList extends LazyBSONObject implements List {
|
|
||||||
|
|
||||||
public LazyBSONList(byte[] data , LazyBSONCallback callback) { super( data , callback ); }
|
|
||||||
public LazyBSONList(byte[] data , int offset , LazyBSONCallback callback) { super( data , offset , callback ); }
|
|
||||||
public LazyBSONList(BSONByteBuffer buffer , LazyBSONCallback callback) { super( buffer , callback ); }
|
|
||||||
public LazyBSONList(BSONByteBuffer buffer , int offset , LazyBSONCallback callback) { super( buffer , offset , callback ); }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains( Object arg0 ){
|
|
||||||
return indexOf(arg0) > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsAll( Collection arg0 ){
|
|
||||||
for ( Object obj : arg0 ) {
|
|
||||||
if ( !contains( obj ) )
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object get( int pos ){
|
|
||||||
return get("" + pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator iterator(){
|
|
||||||
return new LazyBSONListIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int indexOf( Object arg0 ){
|
|
||||||
int pos = 0;
|
|
||||||
Iterator it = iterator();
|
|
||||||
while ( it.hasNext() ) {
|
|
||||||
Object curr = it.next();
|
|
||||||
if ( arg0.equals( curr ) )
|
|
||||||
return pos;
|
|
||||||
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int lastIndexOf( Object arg0 ){
|
|
||||||
int pos = 0;
|
|
||||||
int lastFound = -1;
|
|
||||||
|
|
||||||
Iterator it = iterator();
|
|
||||||
while(it.hasNext()) {
|
|
||||||
Object curr = it.next();
|
|
||||||
if(arg0.equals( curr ))
|
|
||||||
lastFound = pos;
|
|
||||||
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size(){
|
|
||||||
//TODO check the last one and get the key/field name to see the ordinal position in case the array is stored with missing elements.
|
|
||||||
return getElements().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LazyBSONListIterator implements Iterator {
|
|
||||||
List<ElementRecord> elements;
|
|
||||||
int pos=0;
|
|
||||||
|
|
||||||
public LazyBSONListIterator() {
|
|
||||||
elements = getElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext(){
|
|
||||||
return pos < elements.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object next(){
|
|
||||||
return getElementValue(elements.get(pos++));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove(){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ListIterator listIterator( int arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Not Supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ListIterator listIterator(){
|
|
||||||
throw new UnsupportedOperationException( "Not Supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add( Object arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add( int arg0 , Object arg1 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll( Collection arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll( int arg0 , Collection arg1 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear(){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove( Object arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object remove( int arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAll( Collection arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean retainAll( Collection arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object set( int arg0 , Object arg1 ){
|
|
||||||
throw new UnsupportedOperationException( "Read Only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List subList( int arg0 , int arg1 ){
|
|
||||||
throw new UnsupportedOperationException( "Not Supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] toArray(){
|
|
||||||
throw new UnsupportedOperationException( "Not Supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] toArray( Object[] arg0 ){
|
|
||||||
throw new UnsupportedOperationException( "Not Supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,744 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.BSONByteBuffer;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.BSONTimestamp;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.Code;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.CodeWScope;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.MaxKey;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.MinKey;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.Symbol;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author antoine
|
|
||||||
* @author brendan
|
|
||||||
* @author scotthernandez
|
|
||||||
* @author Kilroy Wuz Here
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes", "unused"})
|
|
||||||
public class LazyBSONObject implements BSONObject {
|
|
||||||
|
|
||||||
public LazyBSONObject( byte[] data, LazyBSONCallback callback ){
|
|
||||||
this( BSONByteBuffer.wrap( data ), callback );
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazyBSONObject( byte[] data, int offset, LazyBSONCallback callback ){
|
|
||||||
this( BSONByteBuffer.wrap( data, offset, data.length - offset ), offset, callback );
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazyBSONObject( BSONByteBuffer buffer, LazyBSONCallback callback ){
|
|
||||||
this( buffer, 0, callback );
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazyBSONObject( BSONByteBuffer buffer, int offset, LazyBSONCallback callback ){
|
|
||||||
_callback = callback;
|
|
||||||
_input = buffer;
|
|
||||||
_doc_start_offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ElementRecord {
|
|
||||||
ElementRecord( final String name, final int offset ){
|
|
||||||
this.name = name;
|
|
||||||
this.offset = offset;
|
|
||||||
this.type = getElementType( offset - 1 );
|
|
||||||
this.fieldNameSize = sizeCString( offset );
|
|
||||||
this.valueOffset = offset + fieldNameSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String name;
|
|
||||||
/**
|
|
||||||
* The offset the record begins at.
|
|
||||||
*/
|
|
||||||
final byte type;
|
|
||||||
final int fieldNameSize;
|
|
||||||
final int valueOffset;
|
|
||||||
final int offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LazyBSONKeyIterator implements Iterator<String> {
|
|
||||||
|
|
||||||
public boolean hasNext(){
|
|
||||||
return !isElementEmpty( offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String next(){
|
|
||||||
int fieldSize = sizeCString( offset + 1);
|
|
||||||
int elementSize = getElementBSONSize( offset );
|
|
||||||
String key = _input.getCString( offset + 1);
|
|
||||||
offset += fieldSize + elementSize + 1;
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(){
|
|
||||||
throw new UnsupportedOperationException( "Read only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class LazyBSONKeySet extends ReadOnlySet<String> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method runs in time linear to the total size of all keys in the document.
|
|
||||||
*
|
|
||||||
* @return the number of keys in the document
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int size(){
|
|
||||||
int size = 0;
|
|
||||||
Iterator<String> iter = iterator();
|
|
||||||
while(iter.hasNext()) {
|
|
||||||
iter.next();
|
|
||||||
++size;
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty(){
|
|
||||||
return LazyBSONObject.this.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains( Object o ){
|
|
||||||
for ( String key : this ){
|
|
||||||
if ( key.equals( o ) ){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<String> iterator(){
|
|
||||||
return new LazyBSONKeyIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] toArray(){
|
|
||||||
String[] a = new String[size()];
|
|
||||||
return toArray(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T[] toArray(T[] a) {
|
|
||||||
int size = size();
|
|
||||||
|
|
||||||
T[] localArray = a.length >= size ? a :
|
|
||||||
(T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for ( String key : this ){
|
|
||||||
localArray[i++] = (T) key;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localArray.length > i) {
|
|
||||||
localArray[i] = null;
|
|
||||||
}
|
|
||||||
return localArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add( String e ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove( Object o ){
|
|
||||||
throw new UnsupportedOperationException( "Not supported yet." );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsAll( Collection<?> collection ){
|
|
||||||
for ( Object item : collection ){
|
|
||||||
if ( !contains( item ) ){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LazyBSONEntryIterator implements Iterator<Map.Entry<String, Object>> {
|
|
||||||
|
|
||||||
public boolean hasNext(){
|
|
||||||
return !isElementEmpty( offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map.Entry<String, Object> next(){
|
|
||||||
int fieldSize = sizeCString(offset + 1);
|
|
||||||
int elementSize = getElementBSONSize(offset);
|
|
||||||
String key = _input.getCString(offset + 1);
|
|
||||||
final ElementRecord nextElementRecord = new ElementRecord(key, ++offset);
|
|
||||||
offset += fieldSize + elementSize;
|
|
||||||
return new Map.Entry<String, Object>() {
|
|
||||||
@Override
|
|
||||||
public String getKey() {
|
|
||||||
return nextElementRecord.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValue() {
|
|
||||||
return getElementValue(nextElementRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object setValue(Object value) {
|
|
||||||
throw new UnsupportedOperationException("Read only");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof Map.Entry))
|
|
||||||
return false;
|
|
||||||
Map.Entry e = (Map.Entry) o;
|
|
||||||
return getKey().equals(e.getKey()) && getValue().equals(e.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return getKey().hashCode() ^ getValue().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getKey() + "=" + getValue();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(){
|
|
||||||
throw new UnsupportedOperationException( "Read only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LazyBSONEntrySet extends ReadOnlySet<Map.Entry<String, Object>> {
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return LazyBSONObject.this.keySet().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return LazyBSONObject.this.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(Object o) {
|
|
||||||
Iterator<Map.Entry<String, Object>> iter = iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
if (iter.next().equals(o)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsAll(Collection<?> c) {
|
|
||||||
for (Object cur : c) {
|
|
||||||
if (!contains(cur)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Map.Entry<String, Object>> iterator() {
|
|
||||||
return new LazyBSONEntryIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] toArray() {
|
|
||||||
Map.Entry[] array = new Map.Entry[size()];
|
|
||||||
return toArray(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T[] toArray(T[] a) {
|
|
||||||
int size = size();
|
|
||||||
|
|
||||||
T[] localArray = a.length >= size ? a :
|
|
||||||
(T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
|
|
||||||
|
|
||||||
Iterator<Map.Entry<String, Object>> iter = iterator();
|
|
||||||
int i = 0;
|
|
||||||
while(iter.hasNext()) {
|
|
||||||
localArray[i++] = (T) iter.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localArray.length > i) {
|
|
||||||
localArray[i] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return localArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base class that throws UnsupportedOperationException for any method that writes to the Set
|
|
||||||
abstract class ReadOnlySet<E> implements Set<E> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(E e) {
|
|
||||||
throw new UnsupportedOperationException("Read-only Set");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o) {
|
|
||||||
throw new UnsupportedOperationException("Read-only Set");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll(Collection<? extends E> c) {
|
|
||||||
throw new UnsupportedOperationException("Read-only Set");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean retainAll(Collection<?> c) {
|
|
||||||
throw new UnsupportedOperationException("Read-only Set");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAll(Collection<?> c) {
|
|
||||||
throw new UnsupportedOperationException("Read-only Set");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
throw new UnsupportedOperationException("Read-only Set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object put( String key, Object v ){
|
|
||||||
throw new UnsupportedOperationException( "Object is read only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll( BSONObject o ){
|
|
||||||
throw new UnsupportedOperationException( "Object is read only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll( Map m ){
|
|
||||||
throw new UnsupportedOperationException( "Object is read only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object get( String key ){
|
|
||||||
//get element up to the key
|
|
||||||
ElementRecord element = getElement(key);
|
|
||||||
|
|
||||||
//no found if null/empty
|
|
||||||
if (element == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getElementValue(element);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns the ElementRecord for the given key, or null if not found
|
|
||||||
* @param key the field/key to find
|
|
||||||
* @return ElementRecord for key, or null
|
|
||||||
*/
|
|
||||||
ElementRecord getElement(String key){
|
|
||||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
|
||||||
|
|
||||||
while ( !isElementEmpty( offset ) ){
|
|
||||||
int fieldSize = sizeCString( offset + 1 );
|
|
||||||
int elementSize = getElementBSONSize( offset );
|
|
||||||
String name = _input.getCString( ++offset);
|
|
||||||
|
|
||||||
if (name.equals(key)) {
|
|
||||||
return new ElementRecord( name, offset );
|
|
||||||
}
|
|
||||||
offset += ( fieldSize + elementSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns all the ElementRecords in this document
|
|
||||||
* @return list of ElementRecord
|
|
||||||
*/
|
|
||||||
List<ElementRecord> getElements(){
|
|
||||||
int offset = _doc_start_offset + FIRST_ELMT_OFFSET;
|
|
||||||
ArrayList<ElementRecord> elements = new ArrayList<>();
|
|
||||||
|
|
||||||
while ( !isElementEmpty( offset ) ){
|
|
||||||
int fieldSize = sizeCString( offset + 1 );
|
|
||||||
int elementSize = getElementBSONSize( offset );
|
|
||||||
String name = _input.getCString( ++offset );
|
|
||||||
ElementRecord rec = new ElementRecord( name, offset );
|
|
||||||
elements.add( rec );
|
|
||||||
offset += ( fieldSize + elementSize );
|
|
||||||
}
|
|
||||||
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map toMap(){
|
|
||||||
throw new UnsupportedOperationException( "Not Supported" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object removeField( String key ){
|
|
||||||
throw new UnsupportedOperationException( "Object is read only" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public boolean containsKey( String s ){
|
|
||||||
return containsField( s );
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsField( String s ){
|
|
||||||
return keySet().contains( s );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return the set of all keys in the document
|
|
||||||
*/
|
|
||||||
public Set<String> keySet(){
|
|
||||||
return new LazyBSONKeySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will be more efficient than using a combination of keySet() and get(String key)
|
|
||||||
* @return the set of entries (key, value) in the document
|
|
||||||
*/
|
|
||||||
public Set<Map.Entry<String, Object>> entrySet(){
|
|
||||||
return new LazyBSONEntrySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected boolean isElementEmpty( int offset ){
|
|
||||||
return getElementType( offset ) == BSON.EOO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty(){
|
|
||||||
return isElementEmpty( _doc_start_offset + FIRST_ELMT_OFFSET );
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getBSONSize( final int offset ){
|
|
||||||
return _input.getInt( offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBSONSize(){
|
|
||||||
return getBSONSize( _doc_start_offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
public int pipe(OutputStream os) throws IOException {
|
|
||||||
os.write(_input.array(), _doc_start_offset, getBSONSize());
|
|
||||||
return getBSONSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getElementFieldName( final int offset ){
|
|
||||||
return _input.getCString( offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected byte getElementType( final int offset ){
|
|
||||||
return _input.get( offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected int getElementBSONSize( int offset ){
|
|
||||||
int x = 0;
|
|
||||||
byte type = getElementType( offset++ );
|
|
||||||
int n = sizeCString( offset );
|
|
||||||
int valueOffset = offset + n;
|
|
||||||
switch ( type ){
|
|
||||||
case BSON.EOO:
|
|
||||||
case BSON.UNDEFINED:
|
|
||||||
case BSON.NULL:
|
|
||||||
case BSON.MAXKEY:
|
|
||||||
case BSON.MINKEY:
|
|
||||||
break;
|
|
||||||
case BSON.BOOLEAN:
|
|
||||||
x = 1;
|
|
||||||
break;
|
|
||||||
case BSON.NUMBER_INT:
|
|
||||||
x = 4;
|
|
||||||
break;
|
|
||||||
case BSON.TIMESTAMP:
|
|
||||||
case BSON.DATE:
|
|
||||||
case BSON.NUMBER_LONG:
|
|
||||||
case BSON.NUMBER:
|
|
||||||
x = 8;
|
|
||||||
break;
|
|
||||||
case BSON.OID:
|
|
||||||
x = 12;
|
|
||||||
break;
|
|
||||||
case BSON.SYMBOL:
|
|
||||||
case BSON.CODE:
|
|
||||||
case BSON.STRING:
|
|
||||||
x = _input.getInt( valueOffset ) + 4;
|
|
||||||
break;
|
|
||||||
case BSON.CODE_W_SCOPE:
|
|
||||||
x = _input.getInt( valueOffset );
|
|
||||||
break;
|
|
||||||
case BSON.REF:
|
|
||||||
x = _input.getInt( valueOffset ) + 4 + 12;
|
|
||||||
break;
|
|
||||||
case BSON.OBJECT:
|
|
||||||
case BSON.ARRAY:
|
|
||||||
x = _input.getInt( valueOffset );
|
|
||||||
break;
|
|
||||||
case BSON.BINARY:
|
|
||||||
x = _input.getInt( valueOffset ) + 4 + 1/*subtype*/;
|
|
||||||
break;
|
|
||||||
case BSON.REGEX:
|
|
||||||
// 2 cstrs
|
|
||||||
int part1 = sizeCString( valueOffset );
|
|
||||||
int part2 = sizeCString( valueOffset + part1 );
|
|
||||||
x = part1 + part2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new BSONException( "Invalid type " + type + " for field " + getElementFieldName( offset ) );
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the size of the BSON cstring at the given offset in the buffer
|
|
||||||
* @param offset the offset into the buffer
|
|
||||||
* @return the size of the BSON cstring, including the null terminator
|
|
||||||
*
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected int sizeCString( int offset ){
|
|
||||||
int end = offset;
|
|
||||||
while ( true ){
|
|
||||||
byte b = _input.get( end );
|
|
||||||
if ( b == 0 )
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
return end - offset + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected Object getElementValue( ElementRecord record ){
|
|
||||||
switch ( record.type ){
|
|
||||||
case BSON.EOO:
|
|
||||||
case BSON.UNDEFINED:
|
|
||||||
case BSON.NULL:
|
|
||||||
return null;
|
|
||||||
case BSON.MAXKEY:
|
|
||||||
return new MaxKey();
|
|
||||||
case BSON.MINKEY:
|
|
||||||
return new MinKey();
|
|
||||||
case BSON.BOOLEAN:
|
|
||||||
return ( _input.get( record.valueOffset ) != 0 );
|
|
||||||
case BSON.NUMBER_INT:
|
|
||||||
return _input.getInt( record.valueOffset );
|
|
||||||
case BSON.TIMESTAMP:
|
|
||||||
int inc = _input.getInt( record.valueOffset );
|
|
||||||
int time = _input.getInt( record.valueOffset + 4 );
|
|
||||||
return new BSONTimestamp( time, inc );
|
|
||||||
case BSON.DATE:
|
|
||||||
return new Date( _input.getLong( record.valueOffset ) );
|
|
||||||
case BSON.NUMBER_LONG:
|
|
||||||
return _input.getLong( record.valueOffset );
|
|
||||||
case BSON.NUMBER:
|
|
||||||
return Double.longBitsToDouble( _input.getLong( record.valueOffset ) );
|
|
||||||
case BSON.OID:
|
|
||||||
return new ObjectId( _input.getIntBE( record.valueOffset ),
|
|
||||||
_input.getIntBE( record.valueOffset + 4 ),
|
|
||||||
_input.getIntBE( record.valueOffset + 8 ) );
|
|
||||||
case BSON.SYMBOL:
|
|
||||||
return new Symbol( _input.getUTF8String( record.valueOffset ) );
|
|
||||||
case BSON.CODE:
|
|
||||||
return new Code( _input.getUTF8String( record.valueOffset ) );
|
|
||||||
case BSON.STRING:
|
|
||||||
return _input.getUTF8String( record.valueOffset );
|
|
||||||
case BSON.CODE_W_SCOPE:
|
|
||||||
int strsize = _input.getInt( record.valueOffset + 4 );
|
|
||||||
String code = _input.getUTF8String( record.valueOffset + 4 );
|
|
||||||
BSONObject scope =
|
|
||||||
(BSONObject) _callback.createObject( _input.array(), record.valueOffset + 4 + 4 + strsize );
|
|
||||||
return new CodeWScope( code, scope );
|
|
||||||
case BSON.REF:
|
|
||||||
int csize = _input.getInt( record.valueOffset );
|
|
||||||
String ns = _input.getCString( record.valueOffset + 4 );
|
|
||||||
int oidOffset = record.valueOffset + csize + 4;
|
|
||||||
ObjectId oid = new ObjectId( _input.getIntBE( oidOffset ),
|
|
||||||
_input.getIntBE( oidOffset + 4 ),
|
|
||||||
_input.getIntBE( oidOffset + 8 ) );
|
|
||||||
return _callback.createDBRef( ns, oid );
|
|
||||||
case BSON.OBJECT:
|
|
||||||
return _callback.createObject( _input.array(), record.valueOffset );
|
|
||||||
case BSON.ARRAY:
|
|
||||||
return _callback.createArray( _input.array(), record.valueOffset );
|
|
||||||
case BSON.BINARY:
|
|
||||||
return readBinary( record.valueOffset );
|
|
||||||
case BSON.REGEX:
|
|
||||||
int patternCStringSize = sizeCString( record.valueOffset );
|
|
||||||
String pattern = _input.getCString( record.valueOffset );
|
|
||||||
String flags = _input.getCString( record.valueOffset + patternCStringSize );
|
|
||||||
return Pattern.compile( pattern, BSON.regexFlags( flags ) );
|
|
||||||
default:
|
|
||||||
throw new BSONException(
|
|
||||||
"Invalid type " + record.type + " for field " + getElementFieldName( record.offset ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object readBinary( int valueOffset ){
|
|
||||||
final int totalLen = _input.getInt( valueOffset );
|
|
||||||
valueOffset += 4;
|
|
||||||
final byte bType = _input.get( valueOffset );
|
|
||||||
valueOffset += 1;
|
|
||||||
|
|
||||||
byte[] bin;
|
|
||||||
switch ( bType ){
|
|
||||||
case BSON.B_GENERAL:{
|
|
||||||
bin = new byte[totalLen];
|
|
||||||
for ( int n = 0; n < totalLen; n++ ){
|
|
||||||
bin[n] = _input.get( valueOffset + n );
|
|
||||||
}
|
|
||||||
return bin;
|
|
||||||
}
|
|
||||||
case BSON.B_BINARY:
|
|
||||||
final int len = _input.getInt( valueOffset );
|
|
||||||
if ( len + 4 != totalLen )
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Bad Data Size; Binary Subtype 2. { actual len: " + len + " expected totalLen: " + totalLen
|
|
||||||
+ "}" );
|
|
||||||
valueOffset += 4;
|
|
||||||
bin = new byte[len];
|
|
||||||
for ( int n = 0; n < len; n++ ){
|
|
||||||
bin[n] = _input.get( valueOffset + n );
|
|
||||||
}
|
|
||||||
return bin;
|
|
||||||
case BSON.B_UUID:
|
|
||||||
if ( totalLen != 16 )
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Bad Data Size; Binary Subtype 3 (UUID). { total length: " + totalLen + " != 16" );
|
|
||||||
|
|
||||||
long part1 = _input.getLong( valueOffset );
|
|
||||||
valueOffset += 8;
|
|
||||||
long part2 = _input.getLong( valueOffset );
|
|
||||||
return new UUID( part1, part2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
bin = new byte[totalLen];
|
|
||||||
for ( int n = 0; n < totalLen; n++ ){
|
|
||||||
bin[n] = _input.get( valueOffset + n );
|
|
||||||
}
|
|
||||||
return bin;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getOffset(){
|
|
||||||
return _doc_start_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected byte[] getBytes() {
|
|
||||||
return _input.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
|
|
||||||
LazyBSONObject that = (LazyBSONObject) o;
|
|
||||||
|
|
||||||
return Arrays.equals(this._input.array(), that._input.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(_input.array());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a JSON serialization of this object
|
|
||||||
*
|
|
||||||
* @return JSON serialization
|
|
||||||
*/
|
|
||||||
public String toString(){
|
|
||||||
return com.massivecraft.massivecore.xlib.mongodb.util.JSON.serialize( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In a "normal" (aka not embedded) doc, this will be the offset of the first element.
|
|
||||||
*
|
|
||||||
* In an embedded doc because we use ByteBuffers to avoid unecessary copying the offset must be manually set in
|
|
||||||
* _doc_start_offset
|
|
||||||
*/
|
|
||||||
final static int FIRST_ELMT_OFFSET = 4;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Please use {@link #getOffset()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected final int _doc_start_offset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Please use {@link #getBytes()} to access underlying bytes.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected final BSONByteBuffer _input; // TODO - Guard this with synchronicity?
|
|
||||||
// callback is kept to create sub-objects on the fly
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This field is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected final LazyBSONCallback _callback;
|
|
||||||
private static final Logger log = Logger.getLogger( "org.bson.LazyBSONObject" );
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.BSONByteBuffer;
|
|
||||||
import com.massivecraft.massivecore.xlib.mongodb.DBObject;
|
|
||||||
import com.massivecraft.massivecore.xlib.mongodb.util.JSON;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author scotthernandez
|
|
||||||
* @deprecated Please use {@link com.massivecraft.massivecore.xlib.mongodb.LazyDBList} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings({"unused"})
|
|
||||||
public class LazyDBList extends LazyBSONList implements DBObject {
|
|
||||||
private static final long serialVersionUID = -4415279469780082174L;
|
|
||||||
|
|
||||||
public LazyDBList(byte[] data, LazyBSONCallback callback) { super(data, callback); }
|
|
||||||
public LazyDBList(byte[] data, int offset, LazyBSONCallback callback) { super(data, offset, callback); }
|
|
||||||
public LazyDBList(BSONByteBuffer buffer, LazyBSONCallback callback) { super(buffer, callback); }
|
|
||||||
public LazyDBList(BSONByteBuffer buffer, int offset, LazyBSONCallback callback) { super(buffer, offset, callback); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a JSON serialization of this object
|
|
||||||
* @return JSON serialization
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
return JSON.serialize( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPartialObject(){
|
|
||||||
return _isPartialObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markAsPartialObject(){
|
|
||||||
_isPartialObject = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean _isPartialObject;
|
|
||||||
}
|
|
@ -1,331 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.io.Bits;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.types.ObjectId;
|
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.ARRAY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.BINARY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.BOOLEAN;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_BINARY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_GENERAL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.B_UUID;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.CODE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.CODE_W_SCOPE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.DATE;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.EOO;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.MAXKEY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.MINKEY;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NULL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER_INT;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.NUMBER_LONG;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.OBJECT;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.OID;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.REF;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.REGEX;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.STRING;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.SYMBOL;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.TIMESTAMP;
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.BSON.UNDEFINED;
|
|
||||||
|
|
||||||
// Java
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A new implementation of the bson decoder.
|
|
||||||
*
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class NewBSONDecoder implements BSONDecoder {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BSONObject readObject(final byte [] pData) {
|
|
||||||
_length = pData.length;
|
|
||||||
final BasicBSONCallback c = new BasicBSONCallback();
|
|
||||||
decode(pData, c);
|
|
||||||
return (BSONObject)c.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BSONObject readObject(final InputStream pIn) throws IOException {
|
|
||||||
// Slurp in the data and convert to a byte array.
|
|
||||||
_length = Bits.readInt(pIn);
|
|
||||||
|
|
||||||
if (_data == null || _data.length < _length) {
|
|
||||||
_data = new byte[_length];
|
|
||||||
}
|
|
||||||
|
|
||||||
(new DataInputStream(pIn)).readFully(_data, 4, (_length - 4));
|
|
||||||
|
|
||||||
return readObject(_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int decode(final byte [] pData, final BSONCallback pCallback) {
|
|
||||||
_data = pData;
|
|
||||||
_pos = 4;
|
|
||||||
_callback = pCallback;
|
|
||||||
_decode();
|
|
||||||
return _length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int decode(final InputStream pIn, final BSONCallback pCallback) throws IOException {
|
|
||||||
_length = Bits.readInt(pIn);
|
|
||||||
|
|
||||||
if (_data == null || _data.length < _length) {
|
|
||||||
_data = new byte[_length];
|
|
||||||
}
|
|
||||||
|
|
||||||
(new DataInputStream(pIn)).readFully(_data, 4, (_length - 4));
|
|
||||||
|
|
||||||
return decode(_data, pCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final void _decode() {
|
|
||||||
_callback.objectStart();
|
|
||||||
while (decodeElement());
|
|
||||||
_callback.objectDone();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String readCstr() {
|
|
||||||
int length = 0;
|
|
||||||
final int offset = _pos;
|
|
||||||
|
|
||||||
while (_data[_pos++] != 0) length++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return new String(_data, offset, length, DEFAULT_ENCODING);
|
|
||||||
} catch (final UnsupportedEncodingException uee) {
|
|
||||||
return new String(_data, offset, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String readUtf8Str() {
|
|
||||||
final int length = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
if (length <= 0 || length > MAX_STRING) throw new BSONException("String invalid - corruption");
|
|
||||||
|
|
||||||
try {
|
|
||||||
final String str = new String(_data, _pos, (length - 1), DEFAULT_ENCODING);
|
|
||||||
_pos += length;
|
|
||||||
return str;
|
|
||||||
|
|
||||||
} catch (final UnsupportedEncodingException uee) {
|
|
||||||
throw new BSONException("What is in the db", uee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Object _readBasicObject() {
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
final BSONCallback save = _callback;
|
|
||||||
final BSONCallback _basic = _callback.createBSONCallback();
|
|
||||||
_callback = _basic;
|
|
||||||
_basic.reset();
|
|
||||||
_basic.objectStart(false);
|
|
||||||
|
|
||||||
while( decodeElement() );
|
|
||||||
_callback = save;
|
|
||||||
return _basic.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final void _binary(final String pName) {
|
|
||||||
|
|
||||||
final int totalLen = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
final byte bType = _data[_pos];
|
|
||||||
_pos += 1;
|
|
||||||
|
|
||||||
switch ( bType ){
|
|
||||||
case B_GENERAL: {
|
|
||||||
final byte [] data = new byte[totalLen];
|
|
||||||
|
|
||||||
System.arraycopy(_data, _pos, data, 0, totalLen);
|
|
||||||
_pos += totalLen;
|
|
||||||
|
|
||||||
_callback.gotBinary(pName, bType, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case B_BINARY: {
|
|
||||||
final int len = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
if ( len + 4 != totalLen )
|
|
||||||
throw new IllegalArgumentException( "bad data size subtype 2 len: " + len + " totalLen: " + totalLen );
|
|
||||||
|
|
||||||
final byte [] data = new byte[len];
|
|
||||||
System.arraycopy(_data, _pos, data, 0, len);
|
|
||||||
_pos += len;
|
|
||||||
_callback.gotBinary(pName, bType, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case B_UUID: {
|
|
||||||
if ( totalLen != 16 )
|
|
||||||
throw new IllegalArgumentException( "bad data size subtype 3 len: " + totalLen + " != 16");
|
|
||||||
|
|
||||||
final long part1 = Bits.readLong(_data, _pos);
|
|
||||||
_pos += 8;
|
|
||||||
|
|
||||||
final long part2 = Bits.readLong(_data, _pos);
|
|
||||||
_pos += 8;
|
|
||||||
|
|
||||||
_callback.gotUUID(pName, part1, part2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte [] data = new byte[totalLen];
|
|
||||||
System.arraycopy(_data, _pos, data, 0, totalLen);
|
|
||||||
_pos += totalLen;
|
|
||||||
|
|
||||||
_callback.gotBinary(pName, bType, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final boolean decodeElement() {
|
|
||||||
|
|
||||||
final byte type = _data[_pos];
|
|
||||||
_pos += 1;
|
|
||||||
|
|
||||||
if (type == EOO) return false;
|
|
||||||
|
|
||||||
final String name = readCstr();
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case NULL: { _callback.gotNull(name); return true; }
|
|
||||||
|
|
||||||
case UNDEFINED: { _callback.gotUndefined(name); return true; }
|
|
||||||
|
|
||||||
case BOOLEAN: { _callback.gotBoolean(name, (_data[_pos] > 0)); _pos += 1; return true; }
|
|
||||||
|
|
||||||
case NUMBER: { _callback.gotDouble(name, Double.longBitsToDouble(Bits.readLong(_data, _pos))); _pos += 8; return true; }
|
|
||||||
|
|
||||||
case NUMBER_INT: { _callback.gotInt(name, Bits.readInt(_data, _pos)); _pos += 4; return true; }
|
|
||||||
|
|
||||||
case NUMBER_LONG: {
|
|
||||||
_callback.gotLong(name, Bits.readLong(_data, _pos));
|
|
||||||
_pos += 8;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case SYMBOL: { _callback.gotSymbol(name, readUtf8Str()); return true; }
|
|
||||||
case STRING: { _callback.gotString(name, readUtf8Str()); return true; }
|
|
||||||
|
|
||||||
case OID: {
|
|
||||||
// OID is stored as big endian
|
|
||||||
|
|
||||||
final int p1 = Bits.readIntBE(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
final int p2 = Bits.readIntBE(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
final int p3 = Bits.readIntBE(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
_callback.gotObjectId(name , new ObjectId(p1, p2, p3));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case REF: {
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
final String ns = readCstr();
|
|
||||||
|
|
||||||
final int p1 = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
final int p2 = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
final int p3 = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
_callback.gotDBRef(name , ns, new ObjectId(p1, p2, p3));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DATE: { _callback.gotDate(name , Bits.readLong(_data, _pos)); _pos += 8; return true; }
|
|
||||||
|
|
||||||
|
|
||||||
case REGEX: {
|
|
||||||
_callback.gotRegex(name, readCstr(), readCstr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BINARY: { _binary(name); return true; }
|
|
||||||
|
|
||||||
case CODE: { _callback.gotCode(name, readUtf8Str()); return true; }
|
|
||||||
|
|
||||||
case CODE_W_SCOPE: {
|
|
||||||
_pos += 4;
|
|
||||||
_callback.gotCodeWScope(name, readUtf8Str(), _readBasicObject());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ARRAY:
|
|
||||||
_pos += 4;
|
|
||||||
_callback.arrayStart(name);
|
|
||||||
while (decodeElement());
|
|
||||||
_callback.arrayDone();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case OBJECT:
|
|
||||||
_pos += 4;
|
|
||||||
_callback.objectStart(name);
|
|
||||||
while (decodeElement());
|
|
||||||
_callback.objectDone();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case TIMESTAMP:
|
|
||||||
int i = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
int time = Bits.readInt(_data, _pos);
|
|
||||||
_pos += 4;
|
|
||||||
|
|
||||||
_callback.gotTimestamp(name, time, i);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case MINKEY: _callback.gotMinKey(name); return true;
|
|
||||||
case MAXKEY: _callback.gotMaxKey(name); return true;
|
|
||||||
|
|
||||||
default: throw new UnsupportedOperationException( "BSONDecoder doesn't understand type : " + type + " name: " + name );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int MAX_STRING = ( 32 * 1024 * 1024 );
|
|
||||||
private static final String DEFAULT_ENCODING = "UTF-8";
|
|
||||||
|
|
||||||
private byte [] _data;
|
|
||||||
private int _length;
|
|
||||||
private int _pos = 0;
|
|
||||||
private BSONCallback _callback;
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Transformer.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson;
|
|
||||||
|
|
||||||
public interface Transformer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the new object. return passed in object if no change
|
|
||||||
*/
|
|
||||||
Object transform(Object o);
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.io;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.BSONException;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.nio.Buffer;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pseudo byte buffer, delegates as it is too hard to properly override / extend the ByteBuffer API
|
|
||||||
*
|
|
||||||
* @author brendan
|
|
||||||
*/
|
|
||||||
public class BSONByteBuffer {
|
|
||||||
|
|
||||||
private BSONByteBuffer( ByteBuffer buf ){
|
|
||||||
this.buf = buf;
|
|
||||||
buf.order( ByteOrder.LITTLE_ENDIAN );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BSONByteBuffer wrap( byte[] bytes, int offset, int length ){
|
|
||||||
return new BSONByteBuffer( ByteBuffer.wrap( bytes, offset, length ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BSONByteBuffer wrap( byte[] bytes ){
|
|
||||||
return new BSONByteBuffer( ByteBuffer.wrap( bytes ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte get( int i ){
|
|
||||||
return buf.get(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer get( byte[] bytes, int offset, int length ){
|
|
||||||
return buf.get(bytes, offset, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer get( byte[] bytes ){
|
|
||||||
return buf.get(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] array(){
|
|
||||||
return buf.array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode(){
|
|
||||||
return buf.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
|
|
||||||
BSONByteBuffer that = (BSONByteBuffer) o;
|
|
||||||
|
|
||||||
if (buf != null ? !buf.equals(that.buf) : that.buf != null) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a Little Endian Integer
|
|
||||||
*
|
|
||||||
* @param i Index to read from
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public int getInt( int i ){
|
|
||||||
return getIntLE( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getIntLE( int i ){
|
|
||||||
int x = 0;
|
|
||||||
x |= ( 0xFF & buf.get( i + 0 ) ) << 0;
|
|
||||||
x |= ( 0xFF & buf.get( i + 1 ) ) << 8;
|
|
||||||
x |= ( 0xFF & buf.get( i + 2 ) ) << 16;
|
|
||||||
x |= ( 0xFF & buf.get( i + 3 ) ) << 24;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getIntBE( int i ){
|
|
||||||
int x = 0;
|
|
||||||
x |= ( 0xFF & buf.get( i + 0 ) ) << 24;
|
|
||||||
x |= ( 0xFF & buf.get( i + 1 ) ) << 16;
|
|
||||||
x |= ( 0xFF & buf.get( i + 2 ) ) << 8;
|
|
||||||
x |= ( 0xFF & buf.get( i + 3 ) ) << 0;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLong( int i ){
|
|
||||||
return buf.getLong( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCString(int offset) {
|
|
||||||
int end = offset;
|
|
||||||
while (get(end) != 0) {
|
|
||||||
++end;
|
|
||||||
}
|
|
||||||
int len = end - offset;
|
|
||||||
return new String(array(), offset, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUTF8String(int valueOffset) {
|
|
||||||
int size = getInt(valueOffset) - 1;
|
|
||||||
try {
|
|
||||||
return new String(array(), valueOffset + 4, size, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new BSONException( "Cannot decode string as UTF-8." );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Buffer position( int i ){
|
|
||||||
return buf.position(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Buffer reset(){
|
|
||||||
return buf.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size(){
|
|
||||||
return getInt( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ByteBuffer buf;
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BasicOutputBuffer.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.io;
|
|
||||||
|
|
||||||
import java.io.DataOutput;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
|
|
||||||
public class BasicOutputBuffer extends OutputBuffer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(byte[] b){
|
|
||||||
write( b , 0 , b.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(byte[] b, int off, int len){
|
|
||||||
_ensure( len );
|
|
||||||
System.arraycopy( b , off , _buffer , _cur , len );
|
|
||||||
_cur += len;
|
|
||||||
_size = Math.max( _cur , _size );
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void write(int b){
|
|
||||||
_ensure(1);
|
|
||||||
_buffer[_cur++] = (byte)(0xFF&b);
|
|
||||||
_size = Math.max( _cur , _size );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getPosition(){
|
|
||||||
return _cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void setPosition( int position ){
|
|
||||||
_cur = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void seekEnd(){
|
|
||||||
_cur = _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public void seekStart(){
|
|
||||||
_cur = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return size of data so far
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int size(){
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bytes written
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int pipe( OutputStream out )
|
|
||||||
throws IOException {
|
|
||||||
out.write( _buffer , 0 , _size );
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bytes written
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int pipe( DataOutput out )
|
|
||||||
throws IOException {
|
|
||||||
out.write( _buffer , 0 , _size );
|
|
||||||
return _size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _ensure( int more ){
|
|
||||||
final int need = _cur + more;
|
|
||||||
if ( need < _buffer.length )
|
|
||||||
return;
|
|
||||||
|
|
||||||
int newSize = _buffer.length*2;
|
|
||||||
if ( newSize <= need )
|
|
||||||
newSize = need + 128;
|
|
||||||
|
|
||||||
byte[] n = new byte[newSize];
|
|
||||||
System.arraycopy( _buffer , 0 , n , 0 , _size );
|
|
||||||
_buffer = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public String asString(){
|
|
||||||
return new String( _buffer , 0 , _size );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public String asString( String encoding )
|
|
||||||
throws UnsupportedEncodingException {
|
|
||||||
return new String( _buffer , 0 , _size , encoding );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private int _cur;
|
|
||||||
private int _size;
|
|
||||||
private byte[] _buffer = new byte[512];
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Bits.java
|
|
||||||
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.io;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
public class Bits {
|
|
||||||
|
|
||||||
public static void readFully( InputStream in, byte[] b )
|
|
||||||
throws IOException {
|
|
||||||
readFully( in , b , b.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void readFully( InputStream in, byte[] b, int length )
|
|
||||||
throws IOException {
|
|
||||||
readFully(in, b, 0, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void readFully( InputStream in, byte[] b, int startOffset, int length )
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
if (b.length < length + startOffset) {
|
|
||||||
throw new IllegalArgumentException("Buffer is too small");
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = startOffset;
|
|
||||||
int toRead = length;
|
|
||||||
while ( toRead > 0 ){
|
|
||||||
int bytesRead = in.read( b, offset , toRead );
|
|
||||||
if ( bytesRead < 0 )
|
|
||||||
throw new EOFException();
|
|
||||||
toRead -= bytesRead;
|
|
||||||
offset += bytesRead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int readInt( InputStream in )
|
|
||||||
throws IOException {
|
|
||||||
return readInt( in , new byte[4] );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int readInt( InputStream in , byte[] data )
|
|
||||||
throws IOException {
|
|
||||||
readFully(in, data, 4);
|
|
||||||
return readInt(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int readInt( byte[] data ) {
|
|
||||||
return readInt( data , 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int readInt( byte[] data , int offset ) {
|
|
||||||
int x = 0;
|
|
||||||
x |= ( 0xFF & data[offset+0] ) << 0;
|
|
||||||
x |= ( 0xFF & data[offset+1] ) << 8;
|
|
||||||
x |= ( 0xFF & data[offset+2] ) << 16;
|
|
||||||
x |= ( 0xFF & data[offset+3] ) << 24;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int readIntBE( byte[] data , int offset ) {
|
|
||||||
int x = 0;
|
|
||||||
x |= ( 0xFF & data[offset+0] ) << 24;
|
|
||||||
x |= ( 0xFF & data[offset+1] ) << 16;
|
|
||||||
x |= ( 0xFF & data[offset+2] ) << 8;
|
|
||||||
x |= ( 0xFF & data[offset+3] ) << 0;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long readLong( InputStream in )
|
|
||||||
throws IOException {
|
|
||||||
return readLong( in , new byte[8] );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static long readLong( InputStream in , byte[] data )
|
|
||||||
throws IOException {
|
|
||||||
readFully(in, data, 8);
|
|
||||||
return readLong(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long readLong( byte[] data ) {
|
|
||||||
return readLong( data , 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long readLong( byte[] data , int offset ) {
|
|
||||||
long x = 0;
|
|
||||||
x |= ( 0xFFL & data[offset+0] ) << 0;
|
|
||||||
x |= ( 0xFFL & data[offset+1] ) << 8;
|
|
||||||
x |= ( 0xFFL & data[offset+2] ) << 16;
|
|
||||||
x |= ( 0xFFL & data[offset+3] ) << 24;
|
|
||||||
x |= ( 0xFFL & data[offset+4] ) << 32;
|
|
||||||
x |= ( 0xFFL & data[offset+5] ) << 40;
|
|
||||||
x |= ( 0xFFL & data[offset+6] ) << 48;
|
|
||||||
x |= ( 0xFFL & data[offset+7] ) << 56;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,291 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// OutputBuffer.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.io;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.BSONException;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
|
|
||||||
public abstract class OutputBuffer extends OutputStream {
|
|
||||||
|
|
||||||
public abstract void write(byte[] b);
|
|
||||||
public abstract void write(byte[] b, int off, int len);
|
|
||||||
public abstract void write(int b);
|
|
||||||
|
|
||||||
public abstract int getPosition();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract void setPosition( int position );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract void seekEnd();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract void seekStart();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return size of data so far
|
|
||||||
*/
|
|
||||||
public abstract int size();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bytes written
|
|
||||||
*/
|
|
||||||
public abstract int pipe( OutputStream out )
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* mostly for testing
|
|
||||||
*/
|
|
||||||
public byte [] toByteArray(){
|
|
||||||
try {
|
|
||||||
final ByteArrayOutputStream bout = new ByteArrayOutputStream( size() );
|
|
||||||
pipe( bout );
|
|
||||||
return bout.toByteArray();
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ){
|
|
||||||
throw new RuntimeException( "should be impossible" , ioe );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String asString(){
|
|
||||||
return new String( toByteArray() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String asString( String encoding )
|
|
||||||
throws UnsupportedEncodingException {
|
|
||||||
return new String( toByteArray() , encoding );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String hex(){
|
|
||||||
final StringBuilder buf = new StringBuilder();
|
|
||||||
try {
|
|
||||||
pipe( new OutputStream(){
|
|
||||||
public void write( int b ){
|
|
||||||
String s = Integer.toHexString(0xff & b);
|
|
||||||
|
|
||||||
if (s.length() < 2)
|
|
||||||
buf.append("0");
|
|
||||||
buf.append(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ){
|
|
||||||
throw new RuntimeException( "impossible" );
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String md5(){
|
|
||||||
final MessageDigest md5 ;
|
|
||||||
try {
|
|
||||||
md5 = MessageDigest.getInstance("MD5");
|
|
||||||
}
|
|
||||||
catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new RuntimeException("Error - this implementation of Java doesn't support MD5.");
|
|
||||||
}
|
|
||||||
md5.reset();
|
|
||||||
|
|
||||||
try {
|
|
||||||
pipe( new OutputStream(){
|
|
||||||
public void write( byte[] b , int off , int len ){
|
|
||||||
md5.update( b , off , len );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write( int b ){
|
|
||||||
md5.update( (byte)(b&0xFF) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ){
|
|
||||||
throw new RuntimeException( "impossible" );
|
|
||||||
}
|
|
||||||
|
|
||||||
return com.massivecraft.massivecore.xlib.mongodb.util.Util.toHex( md5.digest() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeInt( int x ){
|
|
||||||
write( x >> 0 );
|
|
||||||
write( x >> 8 );
|
|
||||||
write( x >> 16 );
|
|
||||||
write( x >> 24 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void writeIntBE( int x ){
|
|
||||||
write( x >> 24 );
|
|
||||||
write(x >> 16);
|
|
||||||
write(x >> 8);
|
|
||||||
write(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void writeInt( int pos , int x ){
|
|
||||||
final int save = getPosition();
|
|
||||||
setPosition(pos);
|
|
||||||
writeInt(x);
|
|
||||||
setPosition(save);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeLong( long x ){
|
|
||||||
write( (byte)(0xFFL & ( x >> 0 ) ) );
|
|
||||||
write( (byte)(0xFFL & ( x >> 8 ) ) );
|
|
||||||
write( (byte)(0xFFL & ( x >> 16 ) ) );
|
|
||||||
write( (byte)(0xFFL & ( x >> 24 ) ) );
|
|
||||||
write( (byte)(0xFFL & ( x >> 32 ) ) );
|
|
||||||
write( (byte)(0xFFL & ( x >> 40 ) ) );
|
|
||||||
write( (byte)(0xFFL & ( x >> 48 ) ) );
|
|
||||||
write((byte) (0xFFL & (x >> 56)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeDouble( double x ){
|
|
||||||
writeLong(Double.doubleToRawLongBits(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeString(final String str) {
|
|
||||||
writeInt(0); // making space for size
|
|
||||||
final int strLen = writeCString(str, false);
|
|
||||||
backpatchSize(strLen, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes C string (null-terminated string) to underlying buffer.
|
|
||||||
*
|
|
||||||
* @param str the string
|
|
||||||
* @return number of bytes written
|
|
||||||
*/
|
|
||||||
public int writeCString(final String str) {
|
|
||||||
return writeCString(str, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private int writeCString(final String str, final boolean checkForNullCharacters) {
|
|
||||||
|
|
||||||
final int len = str.length();
|
|
||||||
int total = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < len;/*i gets incremented*/) {
|
|
||||||
final int c = Character.codePointAt(str, i);
|
|
||||||
|
|
||||||
if (checkForNullCharacters && c == 0x0) {
|
|
||||||
throw new BSONException(
|
|
||||||
String.format("BSON cstring '%s' is not valid because it contains a null character at index %d", str, i));
|
|
||||||
}
|
|
||||||
if (c < 0x80) {
|
|
||||||
write((byte) c);
|
|
||||||
total += 1;
|
|
||||||
} else if (c < 0x800) {
|
|
||||||
write((byte) (0xc0 + (c >> 6)));
|
|
||||||
write((byte) (0x80 + (c & 0x3f)));
|
|
||||||
total += 2;
|
|
||||||
} else if (c < 0x10000) {
|
|
||||||
write((byte) (0xe0 + (c >> 12)));
|
|
||||||
write((byte) (0x80 + ((c >> 6) & 0x3f)));
|
|
||||||
write((byte) (0x80 + (c & 0x3f)));
|
|
||||||
total += 3;
|
|
||||||
} else {
|
|
||||||
write((byte) (0xf0 + (c >> 18)));
|
|
||||||
write((byte) (0x80 + ((c >> 12) & 0x3f)));
|
|
||||||
write((byte) (0x80 + ((c >> 6) & 0x3f)));
|
|
||||||
write((byte) (0x80 + (c & 0x3f)));
|
|
||||||
total += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
i += Character.charCount(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
write((byte) 0);
|
|
||||||
total++;
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return getClass().getName() + " size: " + size() + " pos: " + getPosition() ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Backpatches the size of a document or string by writing the size into the four bytes starting at getPosition() -
|
|
||||||
* size.
|
|
||||||
*
|
|
||||||
* @param size the size of the document/string
|
|
||||||
*/
|
|
||||||
public void backpatchSize(final int size) {
|
|
||||||
writeInt(getPosition() - size, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Backpatches the size of a document or string by writing the size into the four bytes starting at {@code getPosition() - size -
|
|
||||||
* additionalOffset}.
|
|
||||||
*
|
|
||||||
* @param size the size of the document/string
|
|
||||||
* @param additionalOffset the offset from the current position to write the size
|
|
||||||
*/
|
|
||||||
protected void backpatchSize(final int size, final int additionalOffset) {
|
|
||||||
writeInt(getPosition() - size - additionalOffset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Truncates the buffer to the given new position, which must be greater than or equal to zero and less than or equal to the current
|
|
||||||
* size of this buffer.
|
|
||||||
*
|
|
||||||
* @param newPosition the position to truncate this buffer to
|
|
||||||
*/
|
|
||||||
public void truncateToPosition(int newPosition) {
|
|
||||||
setPosition(newPosition);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,272 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// PoolOutputBuffer.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.io;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class PoolOutputBuffer extends OutputBuffer {
|
|
||||||
|
|
||||||
public static final int BUF_SIZE = 1024 * 16;
|
|
||||||
|
|
||||||
public PoolOutputBuffer(){
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset(){
|
|
||||||
_cur.reset();
|
|
||||||
_end.reset();
|
|
||||||
|
|
||||||
for ( int i=0; i<_fromPool.size(); i++ )
|
|
||||||
_extra.done( _fromPool.get(i) );
|
|
||||||
_fromPool.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPosition(){
|
|
||||||
return _cur.pos();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void setPosition( int position ){
|
|
||||||
_cur.reset( position );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void seekEnd(){
|
|
||||||
_cur.reset( _end );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void seekStart(){
|
|
||||||
_cur.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public int size(){
|
|
||||||
return _end.pos();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b){
|
|
||||||
write( b , 0 , b.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len){
|
|
||||||
while ( len > 0 ){
|
|
||||||
byte[] bs = _cur();
|
|
||||||
int space = Math.min( bs.length - _cur.y , len );
|
|
||||||
System.arraycopy( b , off , bs , _cur.y , space );
|
|
||||||
_cur.inc( space );
|
|
||||||
len -= space;
|
|
||||||
off += space;
|
|
||||||
_afterWrite();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int b){
|
|
||||||
byte[] bs = _cur();
|
|
||||||
bs[_cur.getAndInc()] = (byte)(b&0xFF);
|
|
||||||
_afterWrite();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void truncateToPosition(final int newPosition) {
|
|
||||||
setPosition(newPosition);
|
|
||||||
_end.reset(_cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _afterWrite(){
|
|
||||||
|
|
||||||
if ( _cur.pos() < _end.pos() ){
|
|
||||||
// we're in the middle of the total space
|
|
||||||
// just need to make sure we're not at the end of a buffer
|
|
||||||
if ( _cur.y == BUF_SIZE )
|
|
||||||
_cur.nextBuffer();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_end.reset( _cur );
|
|
||||||
|
|
||||||
if ( _end.y < BUF_SIZE )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_fromPool.add( _extra.get() );
|
|
||||||
_end.nextBuffer();
|
|
||||||
_cur.reset( _end );
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] _cur(){
|
|
||||||
return _get( _cur.x );
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] _get( int z ){
|
|
||||||
if ( z < 0 )
|
|
||||||
return _mine;
|
|
||||||
return _fromPool.get(z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int pipe( final OutputStream out )
|
|
||||||
throws IOException {
|
|
||||||
|
|
||||||
if ( out == null )
|
|
||||||
throw new NullPointerException( "out is null" );
|
|
||||||
|
|
||||||
int total = 0;
|
|
||||||
|
|
||||||
for ( int i=-1; i<_fromPool.size(); i++ ){
|
|
||||||
final byte[] b = _get( i );
|
|
||||||
final int amt = _end.len( i );
|
|
||||||
if (amt == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out.write( b , 0 , amt );
|
|
||||||
total += amt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class Position {
|
|
||||||
Position(){
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset(){
|
|
||||||
x = -1;
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset( Position other ){
|
|
||||||
x = other.x;
|
|
||||||
y = other.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset( int pos ){
|
|
||||||
x = ( pos / BUF_SIZE ) - 1;
|
|
||||||
y = pos % BUF_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos(){
|
|
||||||
return ( ( x + 1 ) * BUF_SIZE ) + y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getAndInc(){
|
|
||||||
return y++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void inc( int amt ){
|
|
||||||
y += amt;
|
|
||||||
if ( y > BUF_SIZE )
|
|
||||||
throw new IllegalArgumentException( "something is wrong" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void nextBuffer(){
|
|
||||||
if ( y != BUF_SIZE )
|
|
||||||
throw new IllegalArgumentException( "broken" );
|
|
||||||
x++;
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len( int which ){
|
|
||||||
if ( which < x )
|
|
||||||
return BUF_SIZE;
|
|
||||||
else if (which == x)
|
|
||||||
return y;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return x + "," + y;
|
|
||||||
}
|
|
||||||
|
|
||||||
int x; // which buffer -1 == _mine
|
|
||||||
int y; // position in buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
public String asAscii(){
|
|
||||||
if ( _fromPool.size() > 0 )
|
|
||||||
return super.asString();
|
|
||||||
|
|
||||||
final int m = size();
|
|
||||||
final char c[] = m < _chars.length ? _chars : new char[m];
|
|
||||||
|
|
||||||
for ( int i=0; i<m; i++ )
|
|
||||||
c[i] = (char)_mine[i];
|
|
||||||
|
|
||||||
return new String( c , 0 , m );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String asString( String encoding )
|
|
||||||
throws UnsupportedEncodingException {
|
|
||||||
|
|
||||||
|
|
||||||
if ( _fromPool.size() > 0 )
|
|
||||||
return super.asString( encoding );
|
|
||||||
|
|
||||||
if ( encoding.equals( DEFAULT_ENCODING_1 ) || encoding.equals( DEFAULT_ENCODING_2) ){
|
|
||||||
try {
|
|
||||||
return _encoding.decode( _mine , 0 , size() );
|
|
||||||
}
|
|
||||||
catch ( IOException ioe ){
|
|
||||||
// we failed, fall back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new String( _mine , 0 , size() , encoding );
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte[] _mine = new byte[BUF_SIZE];
|
|
||||||
final char[] _chars = new char[BUF_SIZE];
|
|
||||||
final List<byte[]> _fromPool = new ArrayList<>();
|
|
||||||
final UTF8Encoding _encoding = new UTF8Encoding();
|
|
||||||
|
|
||||||
private static final String DEFAULT_ENCODING_1 = "UTF-8";
|
|
||||||
private static final String DEFAULT_ENCODING_2 = "UTF8";
|
|
||||||
|
|
||||||
private final Position _cur = new Position();
|
|
||||||
private final Position _end = new Position();
|
|
||||||
|
|
||||||
private static com.massivecraft.massivecore.xlib.bson.util.SimplePool<byte[]> _extra =
|
|
||||||
new com.massivecraft.massivecore.xlib.bson.util.SimplePool<byte[]>( ( 1024 * 1024 * 10 ) / BUF_SIZE ){
|
|
||||||
|
|
||||||
protected byte[] createNew(){
|
|
||||||
return new byte[BUF_SIZE];
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,201 +0,0 @@
|
|||||||
// UTF8Encoding.java
|
|
||||||
|
|
||||||
/**
|
|
||||||
* from postgresql jdbc driver:
|
|
||||||
* postgresql-jdbc-9.0-801.src
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 1997-2008, PostgreSQL Global Development Group
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
3. Neither the name of the PostgreSQL Global Development Group nor the names
|
|
||||||
of its contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003-2008, PostgreSQL Global Development Group
|
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
//package org.postgresql.core;
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.io;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
|
|
||||||
class UTF8Encoding {
|
|
||||||
|
|
||||||
private static final int MIN_2_BYTES = 0x80;
|
|
||||||
private static final int MIN_3_BYTES = 0x800;
|
|
||||||
private static final int MIN_4_BYTES = 0x10000;
|
|
||||||
private static final int MAX_CODE_POINT = 0x10ffff;
|
|
||||||
|
|
||||||
private char[] decoderArray = new char[1024];
|
|
||||||
|
|
||||||
// helper for decode
|
|
||||||
private final static void checkByte(int ch, int pos, int len) throws IOException {
|
|
||||||
if ((ch & 0xc0) != 0x80)
|
|
||||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: byte {0} of {1} byte sequence is not 10xxxxxx: {2}",
|
|
||||||
new Object[] { new Integer(pos), new Integer(len), new Integer(ch) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
private final static void checkMinimal(int ch, int minValue) throws IOException {
|
|
||||||
if (ch >= minValue)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int actualLen;
|
|
||||||
switch (minValue) {
|
|
||||||
case MIN_2_BYTES:
|
|
||||||
actualLen = 2;
|
|
||||||
break;
|
|
||||||
case MIN_3_BYTES:
|
|
||||||
actualLen = 3;
|
|
||||||
break;
|
|
||||||
case MIN_4_BYTES:
|
|
||||||
actualLen = 4;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("unexpected minValue passed to checkMinimal: " + minValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
int expectedLen;
|
|
||||||
if (ch < MIN_2_BYTES)
|
|
||||||
expectedLen = 1;
|
|
||||||
else if (ch < MIN_3_BYTES)
|
|
||||||
expectedLen = 2;
|
|
||||||
else if (ch < MIN_4_BYTES)
|
|
||||||
expectedLen = 3;
|
|
||||||
else
|
|
||||||
throw new IllegalArgumentException("unexpected ch passed to checkMinimal: " + ch);
|
|
||||||
|
|
||||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: {0} bytes used to encode a {1} byte value: {2}",
|
|
||||||
new Object[] { new Integer(actualLen), new Integer(expectedLen), new Integer(ch) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom byte[] -> String conversion routine for UTF-8 only.
|
|
||||||
* This is about twice as fast as using the String(byte[],int,int,String)
|
|
||||||
* ctor, at least under JDK 1.4.2. The extra checks for illegal representations
|
|
||||||
* add about 10-15% overhead, but they seem worth it given the number of SQL_ASCII
|
|
||||||
* databases out there.
|
|
||||||
*
|
|
||||||
* @param data the array containing UTF8-encoded data
|
|
||||||
* @param offset the offset of the first byte in <code>data</code> to decode from
|
|
||||||
* @param length the number of bytes to decode
|
|
||||||
* @return a decoded string
|
|
||||||
* @throws IOException if something goes wrong
|
|
||||||
*/
|
|
||||||
public synchronized String decode(byte[] data, int offset, int length) throws IOException {
|
|
||||||
char[] cdata = decoderArray;
|
|
||||||
if (cdata.length < length)
|
|
||||||
cdata = decoderArray = new char[length];
|
|
||||||
|
|
||||||
int in = offset;
|
|
||||||
int out = 0;
|
|
||||||
int end = length + offset;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (in < end)
|
|
||||||
{
|
|
||||||
int ch = data[in++] & 0xff;
|
|
||||||
|
|
||||||
// Convert UTF-8 to 21-bit codepoint.
|
|
||||||
if (ch < 0x80) {
|
|
||||||
// 0xxxxxxx -- length 1.
|
|
||||||
} else if (ch < 0xc0) {
|
|
||||||
// 10xxxxxx -- illegal!
|
|
||||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: initial byte is {0}: {1}",
|
|
||||||
new Object[] { "10xxxxxx", new Integer(ch) }));
|
|
||||||
} else if (ch < 0xe0) {
|
|
||||||
// 110xxxxx 10xxxxxx
|
|
||||||
ch = ((ch & 0x1f) << 6);
|
|
||||||
checkByte(data[in], 2, 2);
|
|
||||||
ch = ch | (data[in++] & 0x3f);
|
|
||||||
checkMinimal(ch, MIN_2_BYTES);
|
|
||||||
} else if (ch < 0xf0) {
|
|
||||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
|
||||||
ch = ((ch & 0x0f) << 12);
|
|
||||||
checkByte(data[in], 2, 3);
|
|
||||||
ch = ch | ((data[in++] & 0x3f) << 6);
|
|
||||||
checkByte(data[in], 3, 3);
|
|
||||||
ch = ch | (data[in++] & 0x3f);
|
|
||||||
checkMinimal(ch, MIN_3_BYTES);
|
|
||||||
} else if (ch < 0xf8) {
|
|
||||||
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
|
||||||
ch = ((ch & 0x07) << 18);
|
|
||||||
checkByte(data[in], 2, 4);
|
|
||||||
ch = ch | ((data[in++] & 0x3f) << 12);
|
|
||||||
checkByte(data[in], 3, 4);
|
|
||||||
ch = ch | ((data[in++] & 0x3f) << 6);
|
|
||||||
checkByte(data[in], 4, 4);
|
|
||||||
ch = ch | (data[in++] & 0x3f);
|
|
||||||
checkMinimal(ch, MIN_4_BYTES);
|
|
||||||
} else {
|
|
||||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: initial byte is {0}: {1}",
|
|
||||||
new Object[] { "11111xxx", new Integer(ch) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch > MAX_CODE_POINT)
|
|
||||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: final value is out of range: {0}",
|
|
||||||
new Integer(ch)));
|
|
||||||
|
|
||||||
// Convert 21-bit codepoint to Java chars:
|
|
||||||
// 0..ffff are represented directly as a single char
|
|
||||||
// 10000..10ffff are represented as a "surrogate pair" of two chars
|
|
||||||
// See: http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
|
|
||||||
|
|
||||||
if (ch > 0xffff) {
|
|
||||||
// Use a surrogate pair to represent it.
|
|
||||||
ch -= 0x10000; // ch is now 0..fffff (20 bits)
|
|
||||||
cdata[out++] = (char) (0xd800 + (ch >> 10)); // top 10 bits
|
|
||||||
cdata[out++] = (char) (0xdc00 + (ch & 0x3ff)); // bottom 10 bits
|
|
||||||
} else if (ch >= 0xd800 && ch < 0xe000) {
|
|
||||||
// Not allowed to encode the surrogate range directly.
|
|
||||||
throw new IOException(MessageFormat.format("Illegal UTF-8 sequence: final value is a surrogate value: {0}",
|
|
||||||
new Integer(ch)));
|
|
||||||
} else {
|
|
||||||
// Normal case.
|
|
||||||
cdata[out++] = (char) ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ArrayIndexOutOfBoundsException a)
|
|
||||||
{
|
|
||||||
throw new IOException("Illegal UTF-8 sequence: multibyte sequence was truncated");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we ran past the end without seeing an exception.
|
|
||||||
if (in > end)
|
|
||||||
throw new IOException("Illegal UTF-8 sequence: multibyte sequence was truncated");
|
|
||||||
|
|
||||||
return new String(cdata, 0, out);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
-->
|
|
||||||
<body>
|
|
||||||
<p>Contains classes implementing I/O operations used by BSON objects.</p>
|
|
||||||
</body>
|
|
@ -1,18 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
-->
|
|
||||||
<body>
|
|
||||||
<p>Contains the base BSON classes and Encoder/Decoder.</p>
|
|
||||||
</body>
|
|
@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BSONTimestamp.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this is used for internal increment values.
|
|
||||||
* for storing normal dates in MongoDB, you should use java.util.Date
|
|
||||||
* <b>time</b> is seconds since epoch
|
|
||||||
* <b>inc<b> is an ordinal
|
|
||||||
*/
|
|
||||||
public class BSONTimestamp implements Comparable<BSONTimestamp>, Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -3268482672267936464L;
|
|
||||||
|
|
||||||
static final boolean D = Boolean.getBoolean( "DEBUG.DBTIMESTAMP" );
|
|
||||||
|
|
||||||
public BSONTimestamp(){
|
|
||||||
_inc = 0;
|
|
||||||
_time = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONTimestamp(int time, int inc ){
|
|
||||||
_time = new Date( time * 1000L );
|
|
||||||
_inc = inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return get time in seconds since epoch
|
|
||||||
*/
|
|
||||||
public int getTime(){
|
|
||||||
if ( _time == null )
|
|
||||||
return 0;
|
|
||||||
return (int)(_time.getTime() / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInc(){
|
|
||||||
return _inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return "TS time:" + _time + " inc:" + _inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(BSONTimestamp ts) {
|
|
||||||
if(getTime() != ts.getTime()) {
|
|
||||||
return getTime() - ts.getTime();
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return getInc() - ts.getInc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + _inc;
|
|
||||||
result = prime * result + getTime();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == this)
|
|
||||||
return true;
|
|
||||||
if (obj instanceof BSONTimestamp) {
|
|
||||||
BSONTimestamp t2 = (BSONTimestamp) obj;
|
|
||||||
return getTime() == t2.getTime() && getInc() == t2.getInc();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int _inc;
|
|
||||||
final Date _time;
|
|
||||||
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BasicBSONList.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.BSONObject;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.util.StringRangeSet;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to allow array <code>DBObject</code>s to be created.
|
|
||||||
* <p>
|
|
||||||
* Note: MongoDB will also create arrays from <code>java.util.List</code>s.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <blockquote><pre>
|
|
||||||
* DBObject obj = new BasicBSONList();
|
|
||||||
* obj.put( "0", value1 );
|
|
||||||
* obj.put( "4", value2 );
|
|
||||||
* obj.put( 2, value3 );
|
|
||||||
* </pre></blockquote>
|
|
||||||
* This simulates the array [ value1, null, value3, null, value2 ] by creating the
|
|
||||||
* <code>DBObject</code> <code>{ "0" : value1, "1" : null, "2" : value3, "3" : null, "4" : value2 }</code>.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* BasicBSONList only supports numeric keys. Passing strings that cannot be converted to ints will cause an
|
|
||||||
* IllegalArgumentException.
|
|
||||||
* <blockquote><pre>
|
|
||||||
* BasicBSONList list = new BasicBSONList();
|
|
||||||
* list.put("1", "bar"); // ok
|
|
||||||
* list.put("1E1", "bar"); // throws exception
|
|
||||||
* </pre></blockquote>
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
public class BasicBSONList extends ArrayList<Object> implements BSONObject {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -4415279469780082174L;
|
|
||||||
|
|
||||||
public BasicBSONList() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts a value at an index.
|
|
||||||
* For interface compatibility. Must be passed a String that is parsable to an int.
|
|
||||||
* @param key the index at which to insert the value
|
|
||||||
* @param v the value to insert
|
|
||||||
* @return the value
|
|
||||||
* @throws IllegalArgumentException if <code>key</code> cannot be parsed into an <code>int</code>
|
|
||||||
*/
|
|
||||||
public Object put( String key , Object v ){
|
|
||||||
return put(_getInt( key ), v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts a value at an index.
|
|
||||||
* This will fill any unset indexes less than <code>index</code> with <code>null</code>.
|
|
||||||
* @param key the index at which to insert the value
|
|
||||||
* @param v the value to insert
|
|
||||||
* @return the value
|
|
||||||
*/
|
|
||||||
public Object put( int key, Object v ) {
|
|
||||||
while ( key >= size() )
|
|
||||||
add( null );
|
|
||||||
set( key , v );
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll( Map m ){
|
|
||||||
for ( Map.Entry entry : (Set<Map.Entry>)m.entrySet() ){
|
|
||||||
put( entry.getKey().toString() , entry.getValue() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll( BSONObject o ){
|
|
||||||
for ( String k : o.keySet() ){
|
|
||||||
put( k , o.get( k ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a value at an index.
|
|
||||||
* For interface compatibility. Must be passed a String that is parsable to an int.
|
|
||||||
* @param key the index
|
|
||||||
* @return the value, if found, or null
|
|
||||||
* @throws IllegalArgumentException if <code>key</code> cannot be parsed into an <code>int</code>
|
|
||||||
*/
|
|
||||||
public Object get( String key ){
|
|
||||||
int i = _getInt( key );
|
|
||||||
if ( i < 0 )
|
|
||||||
return null;
|
|
||||||
if ( i >= size() )
|
|
||||||
return null;
|
|
||||||
return get( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object removeField( String key ){
|
|
||||||
int i = _getInt( key );
|
|
||||||
if ( i < 0 )
|
|
||||||
return null;
|
|
||||||
if ( i >= size() )
|
|
||||||
return null;
|
|
||||||
return remove( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public boolean containsKey( String key ){
|
|
||||||
return containsField(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsField( String key ){
|
|
||||||
int i = _getInt( key , false );
|
|
||||||
if ( i < 0 )
|
|
||||||
return false;
|
|
||||||
return i >= 0 && i < size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> keySet(){
|
|
||||||
return new StringRangeSet(size());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map toMap() {
|
|
||||||
Map m = new HashMap();
|
|
||||||
Iterator i = this.keySet().iterator();
|
|
||||||
while (i.hasNext()) {
|
|
||||||
Object s = i.next();
|
|
||||||
m.put(s, this.get(String.valueOf(s)));
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getInt( String s ){
|
|
||||||
return _getInt( s , true );
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getInt( String s , boolean err ){
|
|
||||||
try {
|
|
||||||
return Integer.parseInt( s );
|
|
||||||
}
|
|
||||||
catch ( Exception e ){
|
|
||||||
if ( err )
|
|
||||||
throw new IllegalArgumentException( "BasicBSONList can only work with numeric keys, not: [" + s + "]" );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Binary.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.BSON;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* generic binary holder
|
|
||||||
*/
|
|
||||||
public class Binary implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 7902997490338209467L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Binary object with the default binary type of 0
|
|
||||||
*
|
|
||||||
* @param data raw data
|
|
||||||
*/
|
|
||||||
public Binary(byte[] data) {
|
|
||||||
this(BSON.B_GENERAL, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Binary object
|
|
||||||
*
|
|
||||||
* @param type type of the field as encoded in BSON
|
|
||||||
* @param data raw data
|
|
||||||
*/
|
|
||||||
public Binary(byte type, byte[] data) {
|
|
||||||
_type = type;
|
|
||||||
_data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getType() {
|
|
||||||
return _type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getData() {
|
|
||||||
return _data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int length() {
|
|
||||||
return _data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(o instanceof Binary)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Binary binary = (Binary) o;
|
|
||||||
|
|
||||||
if (_type != binary._type) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!Arrays.equals(_data, binary._data)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = (int) _type;
|
|
||||||
result = 31 * result + (_data != null ? Arrays.hashCode(_data) : 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
final byte _type;
|
|
||||||
final byte[] _data;
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Code.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* for using the Code type
|
|
||||||
*/
|
|
||||||
public class Code implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 475535263314046697L;
|
|
||||||
|
|
||||||
public Code( String code ){
|
|
||||||
_code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode(){
|
|
||||||
return _code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals( Object o ){
|
|
||||||
if ( ! ( o instanceof Code ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Code c = (Code)o;
|
|
||||||
return _code.equals( c._code );
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode(){
|
|
||||||
return _code.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
final String _code;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// CodeWScope.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.BSONObject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* for using the CodeWScope type
|
|
||||||
*/
|
|
||||||
public class CodeWScope extends Code {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -6284832275113680002L;
|
|
||||||
|
|
||||||
public CodeWScope( String code , BSONObject scope ){
|
|
||||||
super( code );
|
|
||||||
_scope = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BSONObject getScope(){
|
|
||||||
return _scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals( Object o ){
|
|
||||||
if ( ! ( o instanceof CodeWScope ) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CodeWScope c = (CodeWScope)o;
|
|
||||||
return _code.equals( c._code ) && _scope.equals( c._scope );
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode(){
|
|
||||||
return _code.hashCode() ^ _scope.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
final BSONObject _scope;
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent the maximum key value regardless of the key's type
|
|
||||||
*/
|
|
||||||
public class MaxKey implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 5123414776151687185L;
|
|
||||||
|
|
||||||
public MaxKey() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return o instanceof MaxKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "MaxKey";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent the minimum key value regardless of the key's type
|
|
||||||
*/
|
|
||||||
public class MinKey implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 4075901136671855684L;
|
|
||||||
|
|
||||||
public MinKey() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return o instanceof MinKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "MinKey";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,592 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ObjectId.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import java.net.NetworkInterface;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A globally unique identifier for objects.
|
|
||||||
* <p>Consists of 12 bytes, divided as follows:
|
|
||||||
* <blockquote><pre>
|
|
||||||
* <table border="1">
|
|
||||||
* <tr><td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td>
|
|
||||||
* <td>7</td><td>8</td><td>9</td><td>10</td><td>11</td></tr>
|
|
||||||
* <tr><td colspan="4">time</td><td colspan="3">machine</td>
|
|
||||||
* <td colspan="2">pid</td><td colspan="3">inc</td></tr>
|
|
||||||
* </table>
|
|
||||||
* </pre></blockquote>
|
|
||||||
*
|
|
||||||
* @dochub objectids
|
|
||||||
*/
|
|
||||||
public class ObjectId implements Comparable<ObjectId> , java.io.Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -4415279469780082174L;
|
|
||||||
|
|
||||||
static final Logger LOGGER = Logger.getLogger( "org.bson.ObjectId" );
|
|
||||||
|
|
||||||
/** Gets a new object id.
|
|
||||||
* @return the new id
|
|
||||||
*/
|
|
||||||
public static ObjectId get(){
|
|
||||||
return new ObjectId();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an ObjectId using time, machine and inc values. The Java driver has done it this way for a long time, but it
|
|
||||||
* does not match the <a href="http://docs.mongodb.org/manual/reference/object-id/">ObjectId specification</a>,
|
|
||||||
* which requires four values, not three. The next major release of the Java driver will conform to this specification,
|
|
||||||
* but will still need to support clients that are relying on the current behavior. To that end,
|
|
||||||
* the constructors that takes these three arguments are now deprecated in favor of this more explicit factory method,
|
|
||||||
* and in the next major release those constructors will be removed.
|
|
||||||
* <p>
|
|
||||||
* NOTE: This will not break any application that use ObjectIds. The 12-byte representation will be round-trippable from old to new
|
|
||||||
* driver releases.
|
|
||||||
*
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param time time in seconds
|
|
||||||
* @param machine machine ID
|
|
||||||
* @param inc incremental value
|
|
||||||
* @see com.massivecraft.massivecore.xlib.bson.types.ObjectId#ObjectId(int, int, int)
|
|
||||||
* @since 2.12.0
|
|
||||||
*/
|
|
||||||
public static ObjectId createFromLegacyFormat(final int time, final int machine, final int inc) {
|
|
||||||
return new ObjectId(time, machine, inc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Checks if a string could be an <code>ObjectId</code>.
|
|
||||||
* @return whether the string could be an object id
|
|
||||||
*/
|
|
||||||
public static boolean isValid( String s ){
|
|
||||||
if ( s == null )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
final int len = s.length();
|
|
||||||
if ( len != 24 )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for ( int i=0; i<len; i++ ){
|
|
||||||
char c = s.charAt( i );
|
|
||||||
if ( c >= '0' && c <= '9' )
|
|
||||||
continue;
|
|
||||||
if ( c >= 'a' && c <= 'f' )
|
|
||||||
continue;
|
|
||||||
if ( c >= 'A' && c <= 'F' )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Turn an object into an <code>ObjectId</code>, if possible.
|
|
||||||
* Strings will be converted into <code>ObjectId</code>s, if possible, and <code>ObjectId</code>s will
|
|
||||||
* be cast and returned. Passing in <code>null</code> returns <code>null</code>.
|
|
||||||
* @param o the object to convert
|
|
||||||
* @return an <code>ObjectId</code> if it can be massaged, null otherwise
|
|
||||||
*
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static ObjectId massageToObjectId( Object o ){
|
|
||||||
if ( o == null )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if ( o instanceof ObjectId )
|
|
||||||
return (ObjectId)o;
|
|
||||||
|
|
||||||
if ( o instanceof String ){
|
|
||||||
String s = o.toString();
|
|
||||||
if ( isValid( s ) )
|
|
||||||
return new ObjectId( s );
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectId( Date time ){
|
|
||||||
this(time, _genmachine, _nextInc.getAndIncrement());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectId( Date time , int inc ){
|
|
||||||
this( time , _genmachine , inc );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an ObjectId using time, machine and inc values. The Java driver has done it this way for a long time, but it
|
|
||||||
* does not match the <a href="http://docs.mongodb.org/manual/reference/object-id/">ObjectId specification</a>,
|
|
||||||
* which requires four values, not three. The next major release of the Java driver will conform to this specification,
|
|
||||||
* but will still need to support clients that are relying on the current behavior. To that end,
|
|
||||||
* this constructor is now deprecated in favor of the more explicit factory method ObjectId#createFromLegacyFormat(int, int, int)},
|
|
||||||
* and in the next major release this constructor will be removed.
|
|
||||||
*
|
|
||||||
* @see ObjectId#createFromLegacyFormat(int, int, int)
|
|
||||||
* @deprecated {@code ObjectId}'s constructed this way do not conform to
|
|
||||||
* the <a href="http://docs.mongodb.org/manual/reference/object-id/">ObjectId specification</a>.
|
|
||||||
* Please use {@link com.massivecraft.massivecore.xlib.bson.types.ObjectId#ObjectId(byte[])} or
|
|
||||||
* {@link ObjectId#createFromLegacyFormat(int, int, int)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public ObjectId( Date time , int machine , int inc ){
|
|
||||||
_time = (int)(time.getTime() / 1000);
|
|
||||||
_machine = machine;
|
|
||||||
_inc = inc;
|
|
||||||
_new = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Creates a new instance from a string.
|
|
||||||
* @param s the string to convert
|
|
||||||
* @throws IllegalArgumentException if the string is not a valid id
|
|
||||||
*/
|
|
||||||
public ObjectId( String s ){
|
|
||||||
this( s , false );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new instance of {@code ObjectId} from a string.
|
|
||||||
* @param s the string representation of ObjectId. Can contains only [0-9]|[a-f]|[A-F] characters.
|
|
||||||
* @param babble if {@code true} - convert to 'babble' objectId format
|
|
||||||
*
|
|
||||||
* @deprecated 'babble' format is deprecated. Please use {@link #ObjectId(String)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public ObjectId( String s , boolean babble ){
|
|
||||||
|
|
||||||
if ( ! isValid( s ) )
|
|
||||||
throw new IllegalArgumentException( "invalid ObjectId [" + s + "]" );
|
|
||||||
|
|
||||||
if ( babble )
|
|
||||||
s = babbleToMongod( s );
|
|
||||||
|
|
||||||
byte b[] = new byte[12];
|
|
||||||
for ( int i=0; i<b.length; i++ ){
|
|
||||||
b[i] = (byte)Integer.parseInt( s.substring( i*2 , i*2 + 2) , 16 );
|
|
||||||
}
|
|
||||||
ByteBuffer bb = ByteBuffer.wrap( b );
|
|
||||||
_time = bb.getInt();
|
|
||||||
_machine = bb.getInt();
|
|
||||||
_inc = bb.getInt();
|
|
||||||
_new = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an ObjectId given its 12-byte binary representation.
|
|
||||||
* @param b a byte array of length 12
|
|
||||||
*/
|
|
||||||
public ObjectId( byte[] b ){
|
|
||||||
if ( b.length != 12 )
|
|
||||||
throw new IllegalArgumentException( "need 12 bytes" );
|
|
||||||
ByteBuffer bb = ByteBuffer.wrap( b );
|
|
||||||
_time = bb.getInt();
|
|
||||||
_machine = bb.getInt();
|
|
||||||
_inc = bb.getInt();
|
|
||||||
_new = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an ObjectId using time, machine and inc values. The Java driver has done it this way for a long time, but it
|
|
||||||
* does not match the <a href="http://docs.mongodb.org/manual/reference/object-id/">ObjectId specification</a>,
|
|
||||||
* which requires four values, not three. The next major release of the Java driver will conform to this specification,
|
|
||||||
* but we will still need to support clients that are relying on the current behavior. To that end,
|
|
||||||
* this constructor is now deprecated in favor of the more explicit factory method ObjectId#createFromLegacyFormat(int, int, int)},
|
|
||||||
* and in the next major release this constructor will be removed.
|
|
||||||
*
|
|
||||||
* @param time time in seconds
|
|
||||||
* @param machine machine ID
|
|
||||||
* @param inc incremental value
|
|
||||||
* @see ObjectId#createFromLegacyFormat(int, int, int)
|
|
||||||
* @deprecated {@code ObjectId}'s constructed this way do not conform to
|
|
||||||
* the <a href="http://docs.mongodb.org/manual/reference/object-id/">ObjectId specification</a>.
|
|
||||||
* Please use {@link com.massivecraft.massivecore.xlib.bson.types.ObjectId#ObjectId(byte[])} or
|
|
||||||
* {@link ObjectId#createFromLegacyFormat(int, int, int)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public ObjectId(int time, int machine, int inc) {
|
|
||||||
_time = time;
|
|
||||||
_machine = machine;
|
|
||||||
_inc = inc;
|
|
||||||
_new = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a new object id.
|
|
||||||
*/
|
|
||||||
public ObjectId(){
|
|
||||||
_time = (int) (System.currentTimeMillis() / 1000);
|
|
||||||
_machine = _genmachine;
|
|
||||||
_inc = _nextInc.getAndIncrement();
|
|
||||||
_new = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode(){
|
|
||||||
int x = _time;
|
|
||||||
x += ( _machine * 111 );
|
|
||||||
x += ( _inc * 17 );
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals( Object o ){
|
|
||||||
|
|
||||||
if ( this == o )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
ObjectId other = massageToObjectId( o );
|
|
||||||
if ( other == null )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return
|
|
||||||
_time == other._time &&
|
|
||||||
_machine == other._machine &&
|
|
||||||
_inc == other._inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated 'babble' format is deprecated. Please use {@link #toHexString()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String toStringBabble(){
|
|
||||||
return babbleToMongod( toStringMongod() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this instance into a 24-byte hexadecimal string representation.
|
|
||||||
*
|
|
||||||
* @return a string representation of the ObjectId in hexadecimal format
|
|
||||||
*/
|
|
||||||
public String toHexString() {
|
|
||||||
final StringBuilder buf = new StringBuilder(24);
|
|
||||||
|
|
||||||
for (final byte b : toByteArray()) {
|
|
||||||
buf.append(String.format("%02x", b & 0xff));
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a string representation of the ObjectId in hexadecimal format
|
|
||||||
*
|
|
||||||
* @deprecated Please use {@link #toHexString()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public String toStringMongod(){
|
|
||||||
byte b[] = toByteArray();
|
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder(24);
|
|
||||||
|
|
||||||
for ( int i=0; i<b.length; i++ ){
|
|
||||||
int x = b[i] & 0xFF;
|
|
||||||
String s = Integer.toHexString( x );
|
|
||||||
if ( s.length() == 1 )
|
|
||||||
buf.append( "0" );
|
|
||||||
buf.append( s );
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] toByteArray(){
|
|
||||||
byte b[] = new byte[12];
|
|
||||||
ByteBuffer bb = ByteBuffer.wrap( b );
|
|
||||||
// by default BB is big endian like we need
|
|
||||||
bb.putInt( _time );
|
|
||||||
bb.putInt( _machine );
|
|
||||||
bb.putInt( _inc );
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String _pos( String s , int p ){
|
|
||||||
return s.substring( p * 2 , ( p * 2 ) + 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static String babbleToMongod( String b ){
|
|
||||||
if ( ! isValid( b ) )
|
|
||||||
throw new IllegalArgumentException( "invalid object id: " + b );
|
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder( 24 );
|
|
||||||
for ( int i=7; i>=0; i-- )
|
|
||||||
buf.append( _pos( b , i ) );
|
|
||||||
for ( int i=11; i>=8; i-- )
|
|
||||||
buf.append( _pos( b , i ) );
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return toStringMongod();
|
|
||||||
}
|
|
||||||
|
|
||||||
int _compareUnsigned( int i , int j ){
|
|
||||||
long li = 0xFFFFFFFFL;
|
|
||||||
li = i & li;
|
|
||||||
long lj = 0xFFFFFFFFL;
|
|
||||||
lj = j & lj;
|
|
||||||
long diff = li - lj;
|
|
||||||
if (diff < Integer.MIN_VALUE)
|
|
||||||
return Integer.MIN_VALUE;
|
|
||||||
if (diff > Integer.MAX_VALUE)
|
|
||||||
return Integer.MAX_VALUE;
|
|
||||||
return (int) diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int compareTo( ObjectId id ){
|
|
||||||
if ( id == null )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
int x = _compareUnsigned( _time , id._time );
|
|
||||||
if ( x != 0 )
|
|
||||||
return x;
|
|
||||||
|
|
||||||
x = _compareUnsigned( _machine , id._machine );
|
|
||||||
if ( x != 0 )
|
|
||||||
return x;
|
|
||||||
|
|
||||||
return _compareUnsigned( _inc , id._inc );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the timestamp (number of seconds since the Unix epoch).
|
|
||||||
*
|
|
||||||
* @return the timestamp
|
|
||||||
*/
|
|
||||||
public int getTimestamp() {
|
|
||||||
return _time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the timestamp as a {@code Date} instance.
|
|
||||||
*
|
|
||||||
* @return the Date
|
|
||||||
*/
|
|
||||||
public Date getDate() {
|
|
||||||
return new Date(_time * 1000L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the time of this ID, in milliseconds
|
|
||||||
*
|
|
||||||
* @deprecated Please use {@link #getDate()} ()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public long getTime(){
|
|
||||||
return _time * 1000L;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the time of this ID, in seconds.
|
|
||||||
* @deprecated Please use {@link #getTimestamp()} ()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int getTimeSecond() {
|
|
||||||
return _time;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the counter.
|
|
||||||
*
|
|
||||||
* @return the counter
|
|
||||||
* @deprecated Please use the {@link #toByteArray()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int getInc() {
|
|
||||||
return _inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the timestamp.
|
|
||||||
*
|
|
||||||
* @return the timestamp
|
|
||||||
* @deprecated Please use {@link #getTimestamp()} ()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int _time(){
|
|
||||||
return _time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the machine identifier.
|
|
||||||
*
|
|
||||||
* @return the machine identifier
|
|
||||||
* @see #createFromLegacyFormat(int, int, int)
|
|
||||||
* @deprecated Please use {@code #toByteArray()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int getMachine() {
|
|
||||||
return _machine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the machine identifier.
|
|
||||||
*
|
|
||||||
* @return the machine identifier
|
|
||||||
* @see #createFromLegacyFormat(int, int, int)
|
|
||||||
* @deprecated Please use {@link #toByteArray()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int _machine(){
|
|
||||||
return _machine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the counter.
|
|
||||||
*
|
|
||||||
* @return the counter
|
|
||||||
* @see #createFromLegacyFormat(int, int, int)
|
|
||||||
* @deprecated Please use {@link #toByteArray()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public int _inc(){
|
|
||||||
return _inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated 'new' flag breaks the immutability of the {@code ObjectId} class
|
|
||||||
* and will be dropped in 3.x versions of the driver
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public boolean isNew() {
|
|
||||||
return _new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated 'new' flag breaks the immutability of the {@code ObjectId} class
|
|
||||||
* and will be dropped in 3.x versions of the driver
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void notNew(){
|
|
||||||
_new = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the machine identifier.
|
|
||||||
*
|
|
||||||
* @return the machine identifier
|
|
||||||
* @see #createFromLegacyFormat(int, int, int)
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static int getGenMachineId() {
|
|
||||||
return _genmachine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current value of the auto-incrementing counter.
|
|
||||||
*/
|
|
||||||
public static int getCurrentCounter() {
|
|
||||||
return _nextInc.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current value of the auto-incrementing counter.
|
|
||||||
*
|
|
||||||
* @deprecated Please use {@link #getCurrentCounter()} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static int getCurrentInc() {
|
|
||||||
return _nextInc.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
final int _time;
|
|
||||||
final int _machine;
|
|
||||||
final int _inc;
|
|
||||||
|
|
||||||
boolean _new;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This method is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static int _flip( int x ){
|
|
||||||
int z = 0;
|
|
||||||
z |= ( ( x << 24 ) & 0xFF000000 );
|
|
||||||
z |= ( ( x << 8 ) & 0x00FF0000 );
|
|
||||||
z |= ( ( x >> 8 ) & 0x0000FF00 );
|
|
||||||
z |= ( ( x >> 24 ) & 0x000000FF );
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AtomicInteger _nextInc = new AtomicInteger( (new java.util.Random()).nextInt() );
|
|
||||||
|
|
||||||
private static final int _genmachine;
|
|
||||||
static {
|
|
||||||
|
|
||||||
try {
|
|
||||||
// build a 2-byte machine piece based on NICs info
|
|
||||||
int machinePiece;
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
|
|
||||||
while ( e.hasMoreElements() ){
|
|
||||||
NetworkInterface ni = e.nextElement();
|
|
||||||
sb.append( ni.toString() );
|
|
||||||
}
|
|
||||||
machinePiece = sb.toString().hashCode() << 16;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
// exception sometimes happens with IBM JVM, use random
|
|
||||||
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
|
||||||
machinePiece = (new Random().nextInt()) << 16;
|
|
||||||
}
|
|
||||||
LOGGER.fine( "machine piece post: " + Integer.toHexString( machinePiece ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a 2 byte process piece. It must represent not only the JVM but the class loader.
|
|
||||||
// Since static var belong to class loader there could be collisions otherwise
|
|
||||||
final int processPiece;
|
|
||||||
{
|
|
||||||
int processId = new java.util.Random().nextInt();
|
|
||||||
try {
|
|
||||||
processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
|
|
||||||
}
|
|
||||||
catch ( Throwable t ){
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoader loader = ObjectId.class.getClassLoader();
|
|
||||||
int loaderId = loader != null ? System.identityHashCode(loader) : 0;
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(Integer.toHexString(processId));
|
|
||||||
sb.append(Integer.toHexString(loaderId));
|
|
||||||
processPiece = sb.toString().hashCode() & 0xFFFF;
|
|
||||||
LOGGER.fine( "process piece: " + Integer.toHexString( processPiece ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
_genmachine = machinePiece | processPiece;
|
|
||||||
LOGGER.fine( "machine : " + Integer.toHexString( _genmachine ) );
|
|
||||||
}
|
|
||||||
catch ( Exception e ){
|
|
||||||
throw new RuntimeException( e );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Symbol.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.types;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to hold a BSON symbol object, which is an interned string in Ruby
|
|
||||||
*/
|
|
||||||
public class Symbol implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1326269319883146072L;
|
|
||||||
|
|
||||||
public Symbol(String s) {
|
|
||||||
_symbol = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSymbol(){
|
|
||||||
return _symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will compare equal to a String that is equal to the String that this holds
|
|
||||||
* @param o
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null) return false;
|
|
||||||
|
|
||||||
String otherSymbol;
|
|
||||||
if (o instanceof Symbol) {
|
|
||||||
otherSymbol = ((Symbol) o)._symbol;
|
|
||||||
}
|
|
||||||
else if (o instanceof String) {
|
|
||||||
otherSymbol = (String) o;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_symbol != null ? !_symbol.equals(otherSymbol) : otherSymbol != null) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return _symbol != null ? _symbol.hashCode() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString(){
|
|
||||||
return _symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final String _symbol;
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
-->
|
|
||||||
<body>
|
|
||||||
<p>Contains classes implementing various BSON types.</p>
|
|
||||||
</body>
|
|
@ -1,632 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008 Atlassian Pty Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.util.annotations.GuardedBy;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.util.annotations.ThreadSafe;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.util.Assertions.notNull;
|
|
||||||
import static java.util.Collections.unmodifiableCollection;
|
|
||||||
import static java.util.Collections.unmodifiableSet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract base class for COW {@link Map} implementations that delegate to an
|
|
||||||
* internal map.
|
|
||||||
*
|
|
||||||
* @param <K> The key type
|
|
||||||
* @param <V> The value type
|
|
||||||
* @param <M> the internal {@link Map} or extension for things like sorted and
|
|
||||||
* navigable maps.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@ThreadSafe
|
|
||||||
abstract class AbstractCopyOnWriteMap<K, V, M extends Map<K, V>> implements ConcurrentMap<K, V>, Serializable {
|
|
||||||
private static final long serialVersionUID = 4508989182041753878L;
|
|
||||||
|
|
||||||
@GuardedBy("lock")
|
|
||||||
private volatile M delegate;
|
|
||||||
|
|
||||||
// import edu.umd.cs.findbugs.annotations.@SuppressWarnings
|
|
||||||
private final transient Lock lock = new ReentrantLock();
|
|
||||||
|
|
||||||
// private final transient EntrySet entrySet = new EntrySet();
|
|
||||||
// private final transient KeySet keySet = new KeySet();
|
|
||||||
// private final transient Values values = new Values();
|
|
||||||
// private final View.Type viewType;
|
|
||||||
private final View<K, V> view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
|
|
||||||
* initialize the values.
|
|
||||||
*
|
|
||||||
* @param map the initial map to initialize with
|
|
||||||
* @param viewType for writable or read-only key, value and entrySet views
|
|
||||||
*/
|
|
||||||
protected <N extends Map<? extends K, ? extends V>> AbstractCopyOnWriteMap(final N map, final View.Type viewType) {
|
|
||||||
this.delegate = notNull("delegate", copy(notNull("map", map)));
|
|
||||||
this.view = notNull("viewType", viewType).get(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy function, implemented by sub-classes.
|
|
||||||
*
|
|
||||||
* @param <N> the map to copy and return.
|
|
||||||
* @param map the initial values of the newly created map.
|
|
||||||
* @return a new map. Will never be modified after construction.
|
|
||||||
*/
|
|
||||||
@GuardedBy("lock")
|
|
||||||
abstract <N extends Map<? extends K, ? extends V>> M copy(N map);
|
|
||||||
|
|
||||||
//
|
|
||||||
// mutable operations
|
|
||||||
//
|
|
||||||
|
|
||||||
public final void clear() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
set(copy(Collections.<K, V> emptyMap()));
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final V remove(final Object key) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
// short circuit if key doesn't exist
|
|
||||||
if (!delegate.containsKey(key)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.remove(key);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(final Object key, final Object value) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (delegate.containsKey(key) && equals(value, delegate.get(key))) {
|
|
||||||
final M map = copy();
|
|
||||||
map.remove(key);
|
|
||||||
set(map);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean replace(final K key, final V oldValue, final V newValue) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (!delegate.containsKey(key) || !equals(oldValue, delegate.get(key))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final M map = copy();
|
|
||||||
map.put(key, newValue);
|
|
||||||
set(map);
|
|
||||||
return true;
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public V replace(final K key, final V value) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (!delegate.containsKey(key)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.put(key, value);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final V put(final K key, final V value) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.put(key, value);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public V putIfAbsent(final K key, final V value) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (!delegate.containsKey(key)) {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.put(key, value);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return delegate.get(key);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void putAll(final Map<? extends K, ? extends V> t) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
map.putAll(t);
|
|
||||||
set(map);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected M copy() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return copy(delegate);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@GuardedBy("lock")
|
|
||||||
protected void set(final M map) {
|
|
||||||
delegate = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Collection views
|
|
||||||
//
|
|
||||||
|
|
||||||
public final Set<Map.Entry<K, V>> entrySet() {
|
|
||||||
return view.entrySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Set<K> keySet() {
|
|
||||||
return view.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Collection<V> values() {
|
|
||||||
return view.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// delegate operations
|
|
||||||
//
|
|
||||||
|
|
||||||
public final boolean containsKey(final Object key) {
|
|
||||||
return delegate.containsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean containsValue(final Object value) {
|
|
||||||
return delegate.containsValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final V get(final Object key) {
|
|
||||||
return delegate.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isEmpty() {
|
|
||||||
return delegate.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int size() {
|
|
||||||
return delegate.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean equals(final Object o) {
|
|
||||||
return delegate.equals(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int hashCode() {
|
|
||||||
return delegate.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final M getDelegate() {
|
|
||||||
return delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return delegate.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// inner classes
|
|
||||||
//
|
|
||||||
|
|
||||||
private class KeySet extends CollectionView<K> implements Set<K> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Collection<K> getDelegate() {
|
|
||||||
return delegate.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// mutable operations
|
|
||||||
//
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
map.keySet().clear();
|
|
||||||
set(map);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(final Object o) {
|
|
||||||
return AbstractCopyOnWriteMap.this.remove(o) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeAll(final Collection<?> c) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.keySet().removeAll(c);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean retainAll(final Collection<?> c) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.keySet().retainAll(c);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class Values extends CollectionView<V> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Collection<V> getDelegate() {
|
|
||||||
return delegate.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
map.values().clear();
|
|
||||||
set(map);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(final Object o) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (!contains(o)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.values().remove(o);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeAll(final Collection<?> c) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.values().removeAll(c);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean retainAll(final Collection<?> c) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.values().retainAll(c);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class EntrySet extends CollectionView<Entry<K, V>> implements Set<Map.Entry<K, V>> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Collection<java.util.Map.Entry<K, V>> getDelegate() {
|
|
||||||
return delegate.entrySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
map.entrySet().clear();
|
|
||||||
set(map);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(final Object o) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (!contains(o)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.entrySet().remove(o);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeAll(final Collection<?> c) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.entrySet().removeAll(c);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean retainAll(final Collection<?> c) {
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
final M map = copy();
|
|
||||||
try {
|
|
||||||
return map.entrySet().retainAll(c);
|
|
||||||
} finally {
|
|
||||||
set(map);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class UnmodifiableIterator<T> implements Iterator<T> {
|
|
||||||
private final Iterator<T> delegate;
|
|
||||||
|
|
||||||
public UnmodifiableIterator(final Iterator<T> delegate) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return delegate.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public T next() {
|
|
||||||
return delegate.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static abstract class CollectionView<E> implements Collection<E> {
|
|
||||||
|
|
||||||
abstract Collection<E> getDelegate();
|
|
||||||
|
|
||||||
//
|
|
||||||
// delegate operations
|
|
||||||
//
|
|
||||||
|
|
||||||
public final boolean contains(final Object o) {
|
|
||||||
return getDelegate().contains(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean containsAll(final Collection<?> c) {
|
|
||||||
return getDelegate().containsAll(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Iterator<E> iterator() {
|
|
||||||
return new UnmodifiableIterator<>(getDelegate().iterator());
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isEmpty() {
|
|
||||||
return getDelegate().isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int size() {
|
|
||||||
return getDelegate().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Object[] toArray() {
|
|
||||||
return getDelegate().toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final <T> T[] toArray(final T[] a) {
|
|
||||||
return getDelegate().toArray(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return getDelegate().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
return getDelegate().equals(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getDelegate().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// unsupported operations
|
|
||||||
//
|
|
||||||
|
|
||||||
public final boolean add(final E o) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean addAll(final Collection<? extends E> c) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean equals(final Object o1, final Object o2) {
|
|
||||||
if (o1 == null) {
|
|
||||||
return o2 == null;
|
|
||||||
}
|
|
||||||
return o1.equals(o2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides access to the views of the underlying key, value and entry
|
|
||||||
* collections.
|
|
||||||
*/
|
|
||||||
public static abstract class View<K, V> {
|
|
||||||
View() {}
|
|
||||||
|
|
||||||
abstract Set<K> keySet();
|
|
||||||
|
|
||||||
abstract Set<Entry<K, V>> entrySet();
|
|
||||||
|
|
||||||
abstract Collection<V> values();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The different types of {@link View} available
|
|
||||||
*/
|
|
||||||
public enum Type {
|
|
||||||
STABLE {
|
|
||||||
@Override
|
|
||||||
<K, V, M extends Map<K, V>> View<K, V> get(final AbstractCopyOnWriteMap<K, V, M> host) {
|
|
||||||
return host.new Immutable();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
LIVE {
|
|
||||||
@Override
|
|
||||||
<K, V, M extends Map<K, V>> View<K, V> get(final AbstractCopyOnWriteMap<K, V, M> host) {
|
|
||||||
return host.new Mutable();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
abstract <K, V, M extends Map<K, V>> View<K, V> get(AbstractCopyOnWriteMap<K, V, M> host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class Immutable extends View<K, V> implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -4158727180429303818L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<K> keySet() {
|
|
||||||
return unmodifiableSet(delegate.keySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Entry<K, V>> entrySet() {
|
|
||||||
return unmodifiableSet(delegate.entrySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<V> values() {
|
|
||||||
return unmodifiableCollection(delegate.values());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class Mutable extends View<K, V> implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1624520291194797634L;
|
|
||||||
|
|
||||||
private final transient KeySet keySet = new KeySet();
|
|
||||||
private final transient EntrySet entrySet = new EntrySet();
|
|
||||||
private final transient Values values = new Values();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<K> keySet() {
|
|
||||||
return keySet;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<Entry<K, V>> entrySet() {
|
|
||||||
return entrySet;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<V> values() {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
* Copyright (c) 2008 Atlassian Pty Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Design by contract assertions.
|
|
||||||
*
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Assertions {
|
|
||||||
public static <T> T notNull(final String name, final T notNull) throws IllegalArgumentException {
|
|
||||||
if (notNull == null) {
|
|
||||||
throw new NullArgumentException(name);
|
|
||||||
}
|
|
||||||
return notNull;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void isTrue(final String name, final boolean check) throws IllegalArgumentException {
|
|
||||||
if (!check) {
|
|
||||||
throw new IllegalStateException(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void isTrueArgument(final String name, final boolean check) {
|
|
||||||
if (!check) {
|
|
||||||
throw new IllegalArgumentException("state should be: " + name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// /CLOVER:OFF
|
|
||||||
private Assertions() {}
|
|
||||||
|
|
||||||
// /CLOVER:ON
|
|
||||||
|
|
||||||
static class NullArgumentException extends IllegalArgumentException {
|
|
||||||
private static final long serialVersionUID = 6178592463723624585L;
|
|
||||||
|
|
||||||
NullArgumentException(final String name) {
|
|
||||||
super(name + " should not be null!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.util.CopyOnWriteMap.newHashMap;
|
|
||||||
import static java.util.Collections.unmodifiableList;
|
|
||||||
|
|
||||||
class ClassAncestry {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getAncestry
|
|
||||||
*
|
|
||||||
* Walks superclass and interface graph, superclasses first, then
|
|
||||||
* interfaces, to compute an ancestry list. Supertypes are visited left to
|
|
||||||
* right. Duplicates are removed such that no Class will appear in the list
|
|
||||||
* before one of its subtypes.
|
|
||||||
*
|
|
||||||
* Does not need to be synchronized, races are harmless as the Class graph
|
|
||||||
* does not change at runtime.
|
|
||||||
*/
|
|
||||||
public static <T> List<Class<?>> getAncestry(Class<T> c) {
|
|
||||||
final ConcurrentMap<Class<?>, List<Class<?>>> cache = getClassAncestryCache();
|
|
||||||
while (true) {
|
|
||||||
List<Class<?>> cachedResult = cache.get(c);
|
|
||||||
if (cachedResult != null) {
|
|
||||||
return cachedResult;
|
|
||||||
}
|
|
||||||
cache.putIfAbsent(c, computeAncestry(c));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* computeAncestry, starting with children and going back to parents
|
|
||||||
*/
|
|
||||||
private static List<Class<?>> computeAncestry(Class<?> c) {
|
|
||||||
final List<Class<?>> result = new ArrayList<>();
|
|
||||||
result.add(Object.class);
|
|
||||||
computeAncestry(c, result);
|
|
||||||
Collections.reverse(result);
|
|
||||||
return unmodifiableList(new ArrayList<>(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> void computeAncestry(Class<T> c, List<Class<?>> result) {
|
|
||||||
if ((c == null) || (c == Object.class)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// first interfaces (looks backwards but is not)
|
|
||||||
Class<?>[] interfaces = c.getInterfaces();
|
|
||||||
for (int i = interfaces.length - 1; i >= 0; i--) {
|
|
||||||
computeAncestry(interfaces[i], result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// next superclass
|
|
||||||
computeAncestry(c.getSuperclass(), result);
|
|
||||||
|
|
||||||
if (!result.contains(c))
|
|
||||||
result.add(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* classAncestryCache
|
|
||||||
*/
|
|
||||||
private static ConcurrentMap<Class<?>, List<Class<?>>> getClassAncestryCache() {
|
|
||||||
return (_ancestryCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final ConcurrentMap<Class<?>, List<Class<?>>> _ancestryCache = newHashMap();
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ClassMap.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps Class objects to values. A ClassMap is different from a regular Map in
|
|
||||||
* that get(c) does not only look to see if 'c' is a key in the Map, but also
|
|
||||||
* walks the up superclass and interface graph of 'c' to find matches. Derived
|
|
||||||
* matches of this sort are then "cached" in the registry so that matches are
|
|
||||||
* faster on future gets.
|
|
||||||
*
|
|
||||||
* This is a very useful class for Class based registries.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* ClassMap<String> m = new ClassMap<String>(); m.put(Animal.class, "Animal");
|
|
||||||
* m.put(Fox.class, "Fox"); m.Fox.class) --> "Fox" m.get(Dog.class) --> "Animal"
|
|
||||||
*
|
|
||||||
* (assuming Dog.class < Animal.class)
|
|
||||||
*/
|
|
||||||
public class ClassMap<T> {
|
|
||||||
/**
|
|
||||||
* Walks superclass and interface graph, superclasses first, then
|
|
||||||
* interfaces, to compute an ancestry list. Supertypes are visited left to
|
|
||||||
* right. Duplicates are removed such that no Class will appear in the list
|
|
||||||
* before one of its subtypes.
|
|
||||||
*/
|
|
||||||
public static <T> List<Class<?>> getAncestry(Class<T> c) {
|
|
||||||
return ClassAncestry.getAncestry(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class ComputeFunction implements Function<Class<?>, T> {
|
|
||||||
@Override
|
|
||||||
public T apply(Class<?> a) {
|
|
||||||
for (Class<?> cls : getAncestry(a)) {
|
|
||||||
T result = map.get(cls);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<Class<?>, T> map = CopyOnWriteMap.newHashMap();
|
|
||||||
private final Map<Class<?>, T> cache = ComputingMap.create(new ComputeFunction());
|
|
||||||
|
|
||||||
|
|
||||||
public T get(Object key) {
|
|
||||||
return cache.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T put(Class<?> key, T value) {
|
|
||||||
try {
|
|
||||||
return map.put(key, value);
|
|
||||||
} finally {
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T remove(Object key) {
|
|
||||||
try {
|
|
||||||
return map.remove(key);
|
|
||||||
} finally {
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
map.clear();
|
|
||||||
cache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return map.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return map.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
|
|
||||||
import static com.massivecraft.massivecore.xlib.bson.util.Assertions.notNull;
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "deprecation"})
|
|
||||||
final class ComputingMap<K, V> implements Map<K, V>, Function<K, V> {
|
|
||||||
|
|
||||||
public static <K, V> Map<K, V> create(Function<K, V> function) {
|
|
||||||
return new ComputingMap<>(CopyOnWriteMap.<K, V>newHashMap(), function);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ConcurrentMap<K, V> map;
|
|
||||||
private final Function<K, V> function;
|
|
||||||
|
|
||||||
ComputingMap(ConcurrentMap<K, V> map, Function<K, V> function) {
|
|
||||||
this.map = notNull("map", map);
|
|
||||||
this.function = notNull("function", function);
|
|
||||||
}
|
|
||||||
|
|
||||||
public V get(Object key) {
|
|
||||||
while (true) {
|
|
||||||
V v = map.get(key);
|
|
||||||
if (v != null)
|
|
||||||
return v;
|
|
||||||
K k = (K) key;
|
|
||||||
V value = function.apply(k);
|
|
||||||
if (value == null)
|
|
||||||
return null;
|
|
||||||
map.putIfAbsent(k, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public V apply(K k) {
|
|
||||||
return get(k);
|
|
||||||
}
|
|
||||||
|
|
||||||
public V putIfAbsent(K key, V value) {
|
|
||||||
return map.putIfAbsent(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Object key, Object value) {
|
|
||||||
return map.remove(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean replace(K key, V oldValue, V newValue) {
|
|
||||||
return map.replace(key, oldValue, newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public V replace(K key, V value) {
|
|
||||||
return map.replace(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return map.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return map.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsKey(Object key) {
|
|
||||||
return map.containsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsValue(Object value) {
|
|
||||||
return map.containsValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public V put(K key, V value) {
|
|
||||||
return map.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public V remove(Object key) {
|
|
||||||
return map.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putAll(Map<? extends K, ? extends V> m) {
|
|
||||||
map.putAll(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
map.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<K> keySet() {
|
|
||||||
return map.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<V> values() {
|
|
||||||
return map.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
|
||||||
return map.entrySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return map.equals(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return map.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,273 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008 Atlassian Pty Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.util.AbstractCopyOnWriteMap.View.Type;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.util.annotations.GuardedBy;
|
|
||||||
import com.massivecraft.massivecore.xlib.bson.util.annotations.ThreadSafe;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A thread-safe variant of {@link Map} in which all mutative operations (the
|
|
||||||
* "destructive" operations described by {@link Map} put, remove and so on) are
|
|
||||||
* implemented by making a fresh copy of the underlying map.
|
|
||||||
* <p>
|
|
||||||
* This is ordinarily too costly, but may be <em>more</em> efficient than
|
|
||||||
* alternatives when traversal operations vastly out-number mutations, and is
|
|
||||||
* useful when you cannot or don't want to synchronize traversals, yet need to
|
|
||||||
* preclude interference among concurrent threads. The "snapshot" style
|
|
||||||
* iterators on the collections returned by {@link #entrySet()},
|
|
||||||
* {@link #keySet()} and {@link #values()} use a reference to the internal map
|
|
||||||
* at the point that the iterator was created. This map never changes during the
|
|
||||||
* lifetime of the iterator, so interference is impossible and the iterator is
|
|
||||||
* guaranteed not to throw <tt>ConcurrentModificationException</tt>. The
|
|
||||||
* iterators will not reflect additions, removals, or changes to the list since
|
|
||||||
* the iterator was created. Removing elements via these iterators is not
|
|
||||||
* supported. The mutable operations on these collections (remove, retain etc.)
|
|
||||||
* are supported but as with the {@link Map} interface, add and addAll are not
|
|
||||||
* and throw {@link UnsupportedOperationException}.
|
|
||||||
* <p>
|
|
||||||
* The actual copy is performed by an abstract {@link #copy(Map)} method. The
|
|
||||||
* method is responsible for the underlying Map implementation (for instance a
|
|
||||||
* {@link HashMap}, {@link TreeMap}, {@link LinkedHashMap} etc.) and therefore
|
|
||||||
* the semantics of what this map will cope with as far as null keys and values,
|
|
||||||
* iteration ordering etc. See the note below about suitable candidates for
|
|
||||||
* underlying Map implementations
|
|
||||||
* <p>
|
|
||||||
* There are supplied implementations for the common j.u.c {@link Map}
|
|
||||||
* implementations via the {@link CopyOnWriteMap} static {@link Builder}.
|
|
||||||
* <p>
|
|
||||||
* Collection views of the keys, values and entries are optionally
|
|
||||||
* {@link View.Type.LIVE live} or {@link View.Type.STABLE stable}. Live views
|
|
||||||
* are modifiable will cause a copy if a modifying method is called on them.
|
|
||||||
* Methods on these will reflect the current state of the collection, although
|
|
||||||
* iterators will be snapshot style. If the collection views are stable they are
|
|
||||||
* unmodifiable, and will be a snapshot of the state of the map at the time the
|
|
||||||
* collection was asked for.
|
|
||||||
* <p>
|
|
||||||
* <strong>Please note</strong> that the thread-safety guarantees are limited to
|
|
||||||
* the thread-safety of the non-mutative (non-destructive) operations of the
|
|
||||||
* underlying map implementation. For instance some implementations such as
|
|
||||||
* {@link WeakHashMap} and {@link LinkedHashMap} with access ordering are
|
|
||||||
* actually structurally modified by the {@link #get(Object)} method and are
|
|
||||||
* therefore not suitable candidates as delegates for this class.
|
|
||||||
*
|
|
||||||
* @param <K> the key type
|
|
||||||
* @param <V> the value type
|
|
||||||
* @author Jed Wesley-Smith
|
|
||||||
*/
|
|
||||||
@ThreadSafe
|
|
||||||
@SuppressWarnings({"deprecation"})
|
|
||||||
abstract class CopyOnWriteMap<K, V> extends AbstractCopyOnWriteMap<K, V, Map<K, V>> {
|
|
||||||
private static final long serialVersionUID = 7935514534647505917L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a {@link Builder} for a {@link CopyOnWriteMap} instance.
|
|
||||||
*
|
|
||||||
* @param <K> key type
|
|
||||||
* @param <V> value type
|
|
||||||
* @return a fresh builder
|
|
||||||
*/
|
|
||||||
public static <K, V> Builder<K, V> builder() {
|
|
||||||
return new Builder<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a {@link CopyOnWriteMap} and specify all the options.
|
|
||||||
*
|
|
||||||
* @param <K> key type
|
|
||||||
* @param <V> value type
|
|
||||||
*/
|
|
||||||
public static class Builder<K, V> {
|
|
||||||
private View.Type viewType = View.Type.STABLE;
|
|
||||||
private final Map<K, V> initialValues = new HashMap<>();
|
|
||||||
|
|
||||||
Builder() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Views are stable (fixed in time) and unmodifiable.
|
|
||||||
*/
|
|
||||||
public Builder<K, V> stableViews() {
|
|
||||||
viewType = View.Type.STABLE;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Views are live (reflecting concurrent updates) and mutator methods
|
|
||||||
* are supported.
|
|
||||||
*/
|
|
||||||
public Builder<K, V> addAll(final Map<? extends K, ? extends V> values) {
|
|
||||||
initialValues.putAll(values);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Views are live (reflecting concurrent updates) and mutator methods
|
|
||||||
* are supported.
|
|
||||||
*/
|
|
||||||
public Builder<K, V> liveViews() {
|
|
||||||
viewType = View.Type.LIVE;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CopyOnWriteMap<K, V> newHashMap() {
|
|
||||||
return new Hash<>(initialValues, viewType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CopyOnWriteMap<K, V> newLinkedMap() {
|
|
||||||
return new Linked<>(initialValues, viewType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}.
|
|
||||||
* <p>
|
|
||||||
* This map has {@link View.Type.STABLE stable} views.
|
|
||||||
*/
|
|
||||||
public static <K, V> CopyOnWriteMap<K, V> newHashMap() {
|
|
||||||
final Builder<K, V> builder = builder();
|
|
||||||
return builder.newHashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link CopyOnWriteMap} with an underlying {@link HashMap}
|
|
||||||
* using the supplied map as the initial values.
|
|
||||||
* <p>
|
|
||||||
* This map has {@link View.Type.STABLE stable} views.
|
|
||||||
*/
|
|
||||||
public static <K, V> CopyOnWriteMap<K, V> newHashMap(final Map<? extends K, ? extends V> map) {
|
|
||||||
final Builder<K, V> builder = builder();
|
|
||||||
return builder.addAll(map).newHashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link CopyOnWriteMap} with an underlying
|
|
||||||
* {@link LinkedHashMap}. Iterators for this map will be return elements in
|
|
||||||
* insertion order.
|
|
||||||
* <p>
|
|
||||||
* This map has {@link View.Type.STABLE stable} views.
|
|
||||||
*/
|
|
||||||
public static <K, V> CopyOnWriteMap<K, V> newLinkedMap() {
|
|
||||||
final Builder<K, V> builder = builder();
|
|
||||||
return builder.newLinkedMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link CopyOnWriteMap} with an underlying
|
|
||||||
* {@link LinkedHashMap} using the supplied map as the initial values.
|
|
||||||
* Iterators for this map will be return elements in insertion order.
|
|
||||||
* <p>
|
|
||||||
* This map has {@link View.Type.STABLE stable} views.
|
|
||||||
*/
|
|
||||||
public static <K, V> CopyOnWriteMap<K, V> newLinkedMap(final Map<? extends K, ? extends V> map) {
|
|
||||||
final Builder<K, V> builder = builder();
|
|
||||||
return builder.addAll(map).newLinkedMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// constructors
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
|
|
||||||
* initialize the values.
|
|
||||||
*
|
|
||||||
* @param map the initial map to initialize with
|
|
||||||
* @deprecated since 0.0.12 use the versions that explicitly specify
|
|
||||||
* View.Type
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected CopyOnWriteMap(final Map<? extends K, ? extends V> map) {
|
|
||||||
this(map, View.Type.LIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new empty {@link CopyOnWriteMap}.
|
|
||||||
*
|
|
||||||
* @deprecated since 0.0.12 use the versions that explicitly specify
|
|
||||||
* View.Type
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected CopyOnWriteMap() {
|
|
||||||
this(Collections.<K, V> emptyMap(), View.Type.LIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link CopyOnWriteMap} with the supplied {@link Map} to
|
|
||||||
* initialize the values. This map may be optionally modified using any of
|
|
||||||
* the key, entry or value views
|
|
||||||
*
|
|
||||||
* @param map the initial map to initialize with
|
|
||||||
*/
|
|
||||||
protected CopyOnWriteMap(final Map<? extends K, ? extends V> map, final View.Type viewType) {
|
|
||||||
super(map, viewType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new empty {@link CopyOnWriteMap}. This map may be optionally
|
|
||||||
* modified using any of the key, entry or value views
|
|
||||||
*/
|
|
||||||
protected CopyOnWriteMap(final View.Type viewType) {
|
|
||||||
super(Collections.<K, V> emptyMap(), viewType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@GuardedBy("internal-lock")
|
|
||||||
protected abstract <N extends Map<? extends K, ? extends V>> Map<K, V> copy(N map);
|
|
||||||
|
|
||||||
//
|
|
||||||
// inner classes
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uses {@link HashMap} instances as its internal storage.
|
|
||||||
*/
|
|
||||||
static class Hash<K, V> extends CopyOnWriteMap<K, V> {
|
|
||||||
private static final long serialVersionUID = 5221824943734164497L;
|
|
||||||
|
|
||||||
Hash(final Map<? extends K, ? extends V> map, final Type viewType) {
|
|
||||||
super(map, viewType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
|
|
||||||
return new HashMap<>(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uses {@link LinkedHashMap} instances as its internal storage.
|
|
||||||
*/
|
|
||||||
static class Linked<K, V> extends CopyOnWriteMap<K, V> {
|
|
||||||
private static final long serialVersionUID = -8659999465009072124L;
|
|
||||||
|
|
||||||
Linked(final Map<? extends K, ? extends V> map, final Type viewType) {
|
|
||||||
super(map, viewType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <N extends Map<? extends K, ? extends V>> Map<K, V> copy(final N map) {
|
|
||||||
return new LinkedHashMap<>(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
interface Function<A, B> {
|
|
||||||
B apply(A a);
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// SimplePool.java
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public abstract class SimplePool<T> {
|
|
||||||
|
|
||||||
public SimplePool( int max ){
|
|
||||||
_max = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimplePool(){
|
|
||||||
_max = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract T createNew();
|
|
||||||
|
|
||||||
protected boolean ok( T t ){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T get(){
|
|
||||||
T t = _stored.poll();
|
|
||||||
if ( t != null )
|
|
||||||
return t;
|
|
||||||
return createNew();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void done( T t ){
|
|
||||||
if ( ! ok( t ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( _stored.size() > _max )
|
|
||||||
return;
|
|
||||||
_stored.add( t );
|
|
||||||
}
|
|
||||||
|
|
||||||
final int _max;
|
|
||||||
private Queue<T> _stored = new ConcurrentLinkedQueue<>();
|
|
||||||
}
|
|
@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2008-2014 MongoDB, Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class StringRangeSet implements Set<String> {
|
|
||||||
|
|
||||||
private final int size;
|
|
||||||
|
|
||||||
private final static int NUMSTR_LEN = 100;
|
|
||||||
private final static String[] NUMSTRS = new String[100];
|
|
||||||
static {
|
|
||||||
for (int i = 0; i < NUMSTR_LEN; ++i)
|
|
||||||
NUMSTRS[i] = String.valueOf(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringRangeSet(int size) {
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator<String> iterator() {
|
|
||||||
return new Iterator<String>() {
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return index < size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String next() {
|
|
||||||
if (index < NUMSTR_LEN)
|
|
||||||
return NUMSTRS[index++];
|
|
||||||
return String.valueOf(index++);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(String e) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll(Collection<? extends String> c) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(Object o) {
|
|
||||||
int t = Integer.parseInt(String.valueOf(o));
|
|
||||||
return t >= 0 && t < size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsAll(Collection<?> c) {
|
|
||||||
for (Object o : c) {
|
|
||||||
if (!contains(o)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAll(Collection<?> c) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean retainAll(Collection<?> c) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] toArray() {
|
|
||||||
String[] array = new String[size()];
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
if (i < NUMSTR_LEN) {
|
|
||||||
array[i] = NUMSTRS[i];
|
|
||||||
} else {
|
|
||||||
array[i] = String.valueOf(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T[] toArray(T[] a) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
|
||||||
* Released under the Creative Commons Attribution License
|
|
||||||
* (http://creativecommons.org/licenses/by/2.5)
|
|
||||||
* Official home: http://www.jcip.net
|
|
||||||
*
|
|
||||||
* Any republication or derived work distributed in source code form
|
|
||||||
* must include this copyright and license notice.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util.annotations;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The field or method to which this annotation is applied can only be accessed
|
|
||||||
* when holding a particular lock, which may be a built-in (synchronization) lock,
|
|
||||||
* or may be an explicit java.util.concurrent.Lock.
|
|
||||||
*
|
|
||||||
* The argument determines which lock guards the annotated field or method:
|
|
||||||
* <ul>
|
|
||||||
* <li>
|
|
||||||
* <code>this</code> : The intrinsic lock of the object in whose class the field is defined.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* <code>class-name.this</code> : For inner classes, it may be necessary to disambiguate 'this';
|
|
||||||
* the <em>class-name.this</em> designation allows you to specify which 'this' reference is intended
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* <code>itself</code> : For reference fields only; the object to which the field refers.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* <code>field-name</code> : The lock object is referenced by the (instance or static) field
|
|
||||||
* specified by <em>field-name</em>.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* <code>class-name.field-name</code> : The lock object is reference by the static field specified
|
|
||||||
* by <em>class-name.field-name</em>.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* <code>method-name()</code> : The lock object is returned by calling the named nil-ary method.
|
|
||||||
* </li>
|
|
||||||
* <li>
|
|
||||||
* <code>class-name.class</code> : The Class object for the specified class should be used as the lock object.
|
|
||||||
* </li>
|
|
||||||
*
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Deprecated
|
|
||||||
public @interface GuardedBy {
|
|
||||||
String value();
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
|
||||||
* Released under the Creative Commons Attribution License
|
|
||||||
* (http://creativecommons.org/licenses/by/2.5)
|
|
||||||
* Official home: http://www.jcip.net
|
|
||||||
*
|
|
||||||
* Any republication or derived work distributed in source code form
|
|
||||||
* must include this copyright and license notice.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util.annotations;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The class to which this annotation is applied is immutable. This means that
|
|
||||||
* its state cannot be seen to change by callers, which implies that
|
|
||||||
* <ul>
|
|
||||||
* <li> all public fields are final, </li>
|
|
||||||
* <li> all public final reference fields refer to other immutable objects, and </li>
|
|
||||||
* <li> constructors and methods do not publish references to any internal state
|
|
||||||
* which is potentially mutable by the implementation. </li>
|
|
||||||
* </ul>
|
|
||||||
* Immutable objects may still have internal mutable state for purposes of performance
|
|
||||||
* optimization; some state variables may be lazily computed, so long as they are computed
|
|
||||||
* from immutable state and that callers cannot tell the difference.
|
|
||||||
* <p>
|
|
||||||
* Immutable objects are inherently thread-safe; they may be passed between threads or
|
|
||||||
* published without synchronization.
|
|
||||||
*
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Deprecated
|
|
||||||
public @interface Immutable {
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
|
||||||
* Released under the Creative Commons Attribution License
|
|
||||||
* (http://creativecommons.org/licenses/by/2.5)
|
|
||||||
* Official home: http://www.jcip.net
|
|
||||||
*
|
|
||||||
* Any republication or derived work distributed in source code form
|
|
||||||
* must include this copyright and license notice.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util.annotations;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The class to which this annotation is applied is not thread-safe.
|
|
||||||
* This annotation primarily exists for clarifying the non-thread-safety of a class
|
|
||||||
* that might otherwise be assumed to be thread-safe, despite the fact that it is a bad
|
|
||||||
* idea to assume a class is thread-safe without good reason.
|
|
||||||
* @see ThreadSafe
|
|
||||||
*
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Deprecated
|
|
||||||
public @interface NotThreadSafe {
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2005 Brian Goetz and Tim Peierls
|
|
||||||
* Released under the Creative Commons Attribution License
|
|
||||||
* (http://creativecommons.org/licenses/by/2.5)
|
|
||||||
* Official home: http://www.jcip.net
|
|
||||||
*
|
|
||||||
* Any republication or derived work distributed in source code form
|
|
||||||
* must include this copyright and license notice.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.bson.util.annotations;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The class to which this annotation is applied is thread-safe. This means that
|
|
||||||
* no sequences of accesses (reads and writes to public fields, calls to public methods)
|
|
||||||
* may put the object into an invalid state, regardless of the interleaving of those actions
|
|
||||||
* by the runtime, and without requiring any additional synchronization or coordination on the
|
|
||||||
* part of the caller.
|
|
||||||
* @deprecated This class is NOT a part of public API and will be dropped in 3.x versions.
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Deprecated
|
|
||||||
public @interface ThreadSafe {
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Copyright (c) 2008-2014 MongoDB, 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.
|
|
||||||
-->
|
|
||||||
<body>
|
|
||||||
<p>Misc utils used by BSON.</p>
|
|
||||||
</body>
|
|
@ -1,118 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.util.ISO8601Utils;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.ParsePosition;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This type adapter supports three subclasses of date: Date, Timestamp, and
|
|
||||||
* java.sql.Date.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
|
|
||||||
|
|
||||||
// TODO: migrate to streaming adapter
|
|
||||||
|
|
||||||
private final DateFormat enUsFormat;
|
|
||||||
private final DateFormat localFormat;
|
|
||||||
|
|
||||||
DefaultDateTypeAdapter() {
|
|
||||||
this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
|
|
||||||
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultDateTypeAdapter(String datePattern) {
|
|
||||||
this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultDateTypeAdapter(int style) {
|
|
||||||
this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
|
|
||||||
}
|
|
||||||
|
|
||||||
public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
|
|
||||||
this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
|
|
||||||
DateFormat.getDateTimeInstance(dateStyle, timeStyle));
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
|
|
||||||
this.enUsFormat = enUsFormat;
|
|
||||||
this.localFormat = localFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These methods need to be synchronized since JDK DateFormat classes are not thread-safe
|
|
||||||
// See issue 162
|
|
||||||
@Override
|
|
||||||
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
synchronized (localFormat) {
|
|
||||||
String dateFormatAsString = enUsFormat.format(src);
|
|
||||||
return new JsonPrimitive(dateFormatAsString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
throws JsonParseException {
|
|
||||||
if (!(json instanceof JsonPrimitive)) {
|
|
||||||
throw new JsonParseException("The date should be a string value");
|
|
||||||
}
|
|
||||||
Date date = deserializeToDate(json);
|
|
||||||
if (typeOfT == Date.class) {
|
|
||||||
return date;
|
|
||||||
} else if (typeOfT == Timestamp.class) {
|
|
||||||
return new Timestamp(date.getTime());
|
|
||||||
} else if (typeOfT == java.sql.Date.class) {
|
|
||||||
return new java.sql.Date(date.getTime());
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Date deserializeToDate(JsonElement json) {
|
|
||||||
synchronized (localFormat) {
|
|
||||||
try {
|
|
||||||
return localFormat.parse(json.getAsString());
|
|
||||||
} catch (ParseException ignored) {}
|
|
||||||
try {
|
|
||||||
return enUsFormat.parse(json.getAsString());
|
|
||||||
} catch (ParseException ignored) {}
|
|
||||||
try {
|
|
||||||
return ISO8601Utils.parse(json.getAsString(), new ParsePosition(0));
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new JsonSyntaxException(json.getAsString(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(DefaultDateTypeAdapter.class.getSimpleName());
|
|
||||||
sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.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 true then that class or field type
|
|
||||||
* will not be part of the JSON output. For deserialization, if {@link #shouldSkipClass(Class)}
|
|
||||||
* returns true, 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>
|
|
||||||
*
|
|
||||||
* <p>For certain model classes, you may only want to serialize a field, but exclude it for
|
|
||||||
* deserialization. To do that, you can write an {@code ExclusionStrategy} as per normal;
|
|
||||||
* however, you would register it with the
|
|
||||||
* {@link GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)} method.
|
|
||||||
* For example:
|
|
||||||
* <pre class="code">
|
|
||||||
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
|
|
||||||
* Gson gson = new GsonBuilder()
|
|
||||||
* .addDeserializationExclusionStrategy(excludeStrings)
|
|
||||||
* .create();
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*
|
|
||||||
* @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
|
|
||||||
* @see GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)
|
|
||||||
* @see GsonBuilder#addSerializationExclusionStrategy(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);
|
|
||||||
}
|
|
@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 final Field field;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a Field Attributes object from the {@code f}.
|
|
||||||
*
|
|
||||||
* @param f the field to pull attributes from
|
|
||||||
*/
|
|
||||||
public FieldAttributes(Field f) {
|
|
||||||
$Gson$Preconditions.checkNotNull(f);
|
|
||||||
this.field = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the declaring class that contains this field
|
|
||||||
*/
|
|
||||||
public Class<?> getDeclaringClass() {
|
|
||||||
return field.getDeclaringClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the name of the field
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return field.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>For example, assume the following class definition:
|
|
||||||
* <pre class="code">
|
|
||||||
* public class Foo {
|
|
||||||
* private String bar;
|
|
||||||
* private List<String> red;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Type listParameterizedType = 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() {
|
|
||||||
return field.getGenericType();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 field.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 field.getAnnotation(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() {
|
|
||||||
return Arrays.asList(field.getAnnotations());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 (field.getModifiers() & modifier) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 field.isSynthetic();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An enumeration that defines a few standard naming conventions for JSON field names.
|
|
||||||
* This enumeration should be used in conjunction with {@link GsonBuilder}
|
|
||||||
* to configure a {@link Gson} instance to properly translate Java field
|
|
||||||
* names into the desired JSON field names.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
public enum FieldNamingPolicy implements FieldNamingStrategy {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Using this naming policy with Gson will ensure that the field name is
|
|
||||||
* unchanged.
|
|
||||||
*/
|
|
||||||
IDENTITY() {
|
|
||||||
@Override public String translateName(Field f) {
|
|
||||||
return f.getName();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Using this naming policy with Gson will ensure that the first "letter" of the Java
|
|
||||||
* field name is capitalized when serialized to its JSON form.
|
|
||||||
*
|
|
||||||
* <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() {
|
|
||||||
@Override public String translateName(Field f) {
|
|
||||||
return upperCaseFirstLetter(f.getName());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Using this naming policy with Gson will ensure that the first "letter" of the Java
|
|
||||||
* field name is capitalized when serialized to its JSON form 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() {
|
|
||||||
@Override public String translateName(Field f) {
|
|
||||||
return upperCaseFirstLetter(separateCamelCase(f.getName(), " "));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Using this naming policy with Gson will modify the Java Field name from its camel cased
|
|
||||||
* 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() {
|
|
||||||
@Override public String translateName(Field f) {
|
|
||||||
return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
@Override public String translateName(Field f) {
|
|
||||||
return separateCamelCase(f.getName(), "-").toLowerCase(Locale.ENGLISH);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the field name that uses camel-case define word separation into
|
|
||||||
* separate words that are separated by the provided {@code separatorString}.
|
|
||||||
*/
|
|
||||||
static String separateCamelCase(String name, String separator) {
|
|
||||||
StringBuilder translation = new StringBuilder();
|
|
||||||
for (int i = 0; i < name.length(); i++) {
|
|
||||||
char character = name.charAt(i);
|
|
||||||
if (Character.isUpperCase(character) && translation.length() != 0) {
|
|
||||||
translation.append(separator);
|
|
||||||
}
|
|
||||||
translation.append(character);
|
|
||||||
}
|
|
||||||
return translation.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures the JSON field names begins with an upper case letter.
|
|
||||||
*/
|
|
||||||
static String upperCaseFirstLetter(String name) {
|
|
||||||
StringBuilder fieldNameBuilder = new StringBuilder();
|
|
||||||
int index = 0;
|
|
||||||
char firstCharacter = name.charAt(index);
|
|
||||||
|
|
||||||
while (index < name.length() - 1) {
|
|
||||||
if (Character.isLetter(firstCharacter)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldNameBuilder.append(firstCharacter);
|
|
||||||
firstCharacter = name.charAt(++index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == name.length()) {
|
|
||||||
return fieldNameBuilder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Character.isUpperCase(firstCharacter)) {
|
|
||||||
String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), name, ++index);
|
|
||||||
return fieldNameBuilder.append(modifiedTarget).toString();
|
|
||||||
} else {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
|
|
||||||
return (indexOfSubstring < srcString.length())
|
|
||||||
? firstCharacter + srcString.substring(indexOfSubstring)
|
|
||||||
: String.valueOf(firstCharacter);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,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 com.massivecraft.massivecore.xlib.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,971 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.annotations.Expose;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.annotations.Since;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.ConstructorConstructor;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.Excluder;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.Primitives;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.Streams;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.*;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.MalformedJsonException;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.concurrent.atomic.AtomicLongArray;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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. Gson instances are Thread-safe so you can reuse them freely across multiple
|
|
||||||
* threads.
|
|
||||||
*
|
|
||||||
* <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 deserializing 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 TypeToken
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
* @author Jesse Wilson
|
|
||||||
*/
|
|
||||||
public final class Gson {
|
|
||||||
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
|
||||||
static final boolean DEFAULT_LENIENT = false;
|
|
||||||
static final boolean DEFAULT_PRETTY_PRINT = false;
|
|
||||||
static final boolean DEFAULT_ESCAPE_HTML = true;
|
|
||||||
static final boolean DEFAULT_SERIALIZE_NULLS = false;
|
|
||||||
static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
|
|
||||||
static final boolean DEFAULT_SPECIALIZE_FLOAT_VALUES = false;
|
|
||||||
|
|
||||||
private static final TypeToken<?> NULL_KEY_SURROGATE = new TypeToken<Object>() {};
|
|
||||||
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This thread local guards against reentrant calls to getAdapter(). In
|
|
||||||
* certain object graphs, creating an adapter for a type may recursively
|
|
||||||
* require an adapter for the same type! Without intervention, the recursive
|
|
||||||
* lookup would stack overflow. We cheat by returning a proxy type adapter.
|
|
||||||
* The proxy is wired up once the initial adapter has been created.
|
|
||||||
*/
|
|
||||||
private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls
|
|
||||||
= new ThreadLocal<>();
|
|
||||||
|
|
||||||
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final List<TypeAdapterFactory> factories;
|
|
||||||
private final ConstructorConstructor constructorConstructor;
|
|
||||||
|
|
||||||
private final Excluder excluder;
|
|
||||||
private final FieldNamingStrategy fieldNamingStrategy;
|
|
||||||
private final boolean serializeNulls;
|
|
||||||
private final boolean htmlSafe;
|
|
||||||
private final boolean generateNonExecutableJson;
|
|
||||||
private final boolean prettyPrinting;
|
|
||||||
private final boolean lenient;
|
|
||||||
private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 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 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"</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(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY,
|
|
||||||
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
|
|
||||||
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
|
|
||||||
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
|
|
||||||
LongSerializationPolicy.DEFAULT, Collections.<TypeAdapterFactory>emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
|
|
||||||
final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
|
||||||
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
|
|
||||||
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
|
|
||||||
LongSerializationPolicy longSerializationPolicy,
|
|
||||||
List<TypeAdapterFactory> typeAdapterFactories) {
|
|
||||||
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
|
|
||||||
this.excluder = excluder;
|
|
||||||
this.fieldNamingStrategy = fieldNamingStrategy;
|
|
||||||
this.serializeNulls = serializeNulls;
|
|
||||||
this.generateNonExecutableJson = generateNonExecutableGson;
|
|
||||||
this.htmlSafe = htmlSafe;
|
|
||||||
this.prettyPrinting = prettyPrinting;
|
|
||||||
this.lenient = lenient;
|
|
||||||
|
|
||||||
List<TypeAdapterFactory> factories = new ArrayList<>();
|
|
||||||
|
|
||||||
// built-in type adapters that cannot be overridden
|
|
||||||
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
|
|
||||||
factories.add(ObjectTypeAdapter.FACTORY);
|
|
||||||
|
|
||||||
// the excluder must precede all adapters that handle user-defined types
|
|
||||||
factories.add(excluder);
|
|
||||||
|
|
||||||
// user's type adapters
|
|
||||||
factories.addAll(typeAdapterFactories);
|
|
||||||
|
|
||||||
// type adapters for basic platform types
|
|
||||||
factories.add(TypeAdapters.STRING_FACTORY);
|
|
||||||
factories.add(TypeAdapters.INTEGER_FACTORY);
|
|
||||||
factories.add(TypeAdapters.BOOLEAN_FACTORY);
|
|
||||||
factories.add(TypeAdapters.BYTE_FACTORY);
|
|
||||||
factories.add(TypeAdapters.SHORT_FACTORY);
|
|
||||||
TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
|
|
||||||
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
|
|
||||||
factories.add(TypeAdapters.newFactory(double.class, Double.class,
|
|
||||||
doubleAdapter(serializeSpecialFloatingPointValues)));
|
|
||||||
factories.add(TypeAdapters.newFactory(float.class, Float.class,
|
|
||||||
floatAdapter(serializeSpecialFloatingPointValues)));
|
|
||||||
factories.add(TypeAdapters.NUMBER_FACTORY);
|
|
||||||
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
|
|
||||||
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
|
|
||||||
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
|
|
||||||
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
|
|
||||||
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
|
|
||||||
factories.add(TypeAdapters.CHARACTER_FACTORY);
|
|
||||||
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
|
|
||||||
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
|
|
||||||
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
|
|
||||||
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
|
|
||||||
factories.add(TypeAdapters.URL_FACTORY);
|
|
||||||
factories.add(TypeAdapters.URI_FACTORY);
|
|
||||||
factories.add(TypeAdapters.UUID_FACTORY);
|
|
||||||
factories.add(TypeAdapters.CURRENCY_FACTORY);
|
|
||||||
factories.add(TypeAdapters.LOCALE_FACTORY);
|
|
||||||
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
|
|
||||||
factories.add(TypeAdapters.BIT_SET_FACTORY);
|
|
||||||
factories.add(DateTypeAdapter.FACTORY);
|
|
||||||
factories.add(TypeAdapters.CALENDAR_FACTORY);
|
|
||||||
factories.add(TimeTypeAdapter.FACTORY);
|
|
||||||
factories.add(SqlDateTypeAdapter.FACTORY);
|
|
||||||
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
|
|
||||||
factories.add(ArrayTypeAdapter.FACTORY);
|
|
||||||
factories.add(TypeAdapters.CLASS_FACTORY);
|
|
||||||
|
|
||||||
// type adapters for composite and user-defined types
|
|
||||||
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
|
|
||||||
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
|
|
||||||
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
|
|
||||||
factories.add(jsonAdapterFactory);
|
|
||||||
factories.add(TypeAdapters.ENUM_FACTORY);
|
|
||||||
factories.add(new ReflectiveTypeAdapterFactory(
|
|
||||||
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
|
|
||||||
|
|
||||||
this.factories = Collections.unmodifiableList(factories);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Excluder excluder() {
|
|
||||||
return excluder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldNamingStrategy fieldNamingStrategy() {
|
|
||||||
return fieldNamingStrategy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean serializeNulls() {
|
|
||||||
return serializeNulls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean htmlSafe() {
|
|
||||||
return htmlSafe;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
|
|
||||||
if (serializeSpecialFloatingPointValues) {
|
|
||||||
return TypeAdapters.DOUBLE;
|
|
||||||
}
|
|
||||||
return new TypeAdapter<Number>() {
|
|
||||||
@Override public Double read(JsonReader in) throws IOException {
|
|
||||||
if (in.peek() == JsonToken.NULL) {
|
|
||||||
in.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return in.nextDouble();
|
|
||||||
}
|
|
||||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
double doubleValue = value.doubleValue();
|
|
||||||
checkValidFloatingPoint(doubleValue);
|
|
||||||
out.value(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) {
|
|
||||||
if (serializeSpecialFloatingPointValues) {
|
|
||||||
return TypeAdapters.FLOAT;
|
|
||||||
}
|
|
||||||
return new TypeAdapter<Number>() {
|
|
||||||
@Override public Float read(JsonReader in) throws IOException {
|
|
||||||
if (in.peek() == JsonToken.NULL) {
|
|
||||||
in.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (float) in.nextDouble();
|
|
||||||
}
|
|
||||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float floatValue = value.floatValue();
|
|
||||||
checkValidFloatingPoint(floatValue);
|
|
||||||
out.value(value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static void checkValidFloatingPoint(double value) {
|
|
||||||
if (Double.isNaN(value) || Double.isInfinite(value)) {
|
|
||||||
throw new IllegalArgumentException(value
|
|
||||||
+ " is not a valid double value as per JSON specification. To override this"
|
|
||||||
+ " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) {
|
|
||||||
if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) {
|
|
||||||
return TypeAdapters.LONG;
|
|
||||||
}
|
|
||||||
return new TypeAdapter<Number>() {
|
|
||||||
@Override public Number read(JsonReader in) throws IOException {
|
|
||||||
if (in.peek() == JsonToken.NULL) {
|
|
||||||
in.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return in.nextLong();
|
|
||||||
}
|
|
||||||
@Override public void write(JsonWriter out, Number value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
out.value(value.toString());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TypeAdapter<AtomicLong> atomicLongAdapter(final TypeAdapter<Number> longAdapter) {
|
|
||||||
return new TypeAdapter<AtomicLong>() {
|
|
||||||
@Override public void write(JsonWriter out, AtomicLong value) throws IOException {
|
|
||||||
longAdapter.write(out, value.get());
|
|
||||||
}
|
|
||||||
@Override public AtomicLong read(JsonReader in) throws IOException {
|
|
||||||
Number value = longAdapter.read(in);
|
|
||||||
return new AtomicLong(value.longValue());
|
|
||||||
}
|
|
||||||
}.nullSafe();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TypeAdapter<AtomicLongArray> atomicLongArrayAdapter(final TypeAdapter<Number> longAdapter) {
|
|
||||||
return new TypeAdapter<AtomicLongArray>() {
|
|
||||||
@Override public void write(JsonWriter out, AtomicLongArray value) throws IOException {
|
|
||||||
out.beginArray();
|
|
||||||
for (int i = 0, length = value.length(); i < length; i++) {
|
|
||||||
longAdapter.write(out, value.get(i));
|
|
||||||
}
|
|
||||||
out.endArray();
|
|
||||||
}
|
|
||||||
@Override public AtomicLongArray read(JsonReader in) throws IOException {
|
|
||||||
List<Long> list = new ArrayList<>();
|
|
||||||
in.beginArray();
|
|
||||||
while (in.hasNext()) {
|
|
||||||
long value = longAdapter.read(in).longValue();
|
|
||||||
list.add(value);
|
|
||||||
}
|
|
||||||
in.endArray();
|
|
||||||
int length = list.size();
|
|
||||||
AtomicLongArray array = new AtomicLongArray(length);
|
|
||||||
for (int i = 0; i < length; ++i) {
|
|
||||||
array.set(i, list.get(i));
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
}.nullSafe();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type adapter for {@code} type.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
|
||||||
* deserialize {@code type}.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
|
|
||||||
TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
|
|
||||||
if (cached != null) {
|
|
||||||
return (TypeAdapter<T>) cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
|
|
||||||
boolean requiresThreadLocalCleanup = false;
|
|
||||||
if (threadCalls == null) {
|
|
||||||
threadCalls = new HashMap<>();
|
|
||||||
calls.set(threadCalls);
|
|
||||||
requiresThreadLocalCleanup = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the key and value type parameters always agree
|
|
||||||
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
|
|
||||||
if (ongoingCall != null) {
|
|
||||||
return ongoingCall;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
FutureTypeAdapter<T> call = new FutureTypeAdapter<>();
|
|
||||||
threadCalls.put(type, call);
|
|
||||||
|
|
||||||
for (TypeAdapterFactory factory : factories) {
|
|
||||||
TypeAdapter<T> candidate = factory.create(this, type);
|
|
||||||
if (candidate != null) {
|
|
||||||
call.setDelegate(candidate);
|
|
||||||
typeTokenCache.put(type, candidate);
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("GSON cannot handle " + type);
|
|
||||||
} finally {
|
|
||||||
threadCalls.remove(type);
|
|
||||||
|
|
||||||
if (requiresThreadLocalCleanup) {
|
|
||||||
calls.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is used to get an alternate type adapter for the specified type. This is used
|
|
||||||
* to access a type adapter that is overridden by a {@link TypeAdapterFactory} that you
|
|
||||||
* may have registered. This features is typically used when you want to register a type
|
|
||||||
* adapter that does a little bit of work but then delegates further processing to the Gson
|
|
||||||
* default type adapter. Here is an example:
|
|
||||||
* <p>Let's say we want to write a type adapter that counts the number of objects being read
|
|
||||||
* from or written to JSON. We can achieve this by writing a type adapter factory that uses
|
|
||||||
* the <code>getDelegateAdapter</code> method:
|
|
||||||
* <pre> {@code
|
|
||||||
* class StatsTypeAdapterFactory implements TypeAdapterFactory {
|
|
||||||
* public int numReads = 0;
|
|
||||||
* public int numWrites = 0;
|
|
||||||
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
|
||||||
* final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
|
|
||||||
* return new TypeAdapter<T>() {
|
|
||||||
* public void write(JsonWriter out, T value) throws IOException {
|
|
||||||
* ++numWrites;
|
|
||||||
* delegate.write(out, value);
|
|
||||||
* }
|
|
||||||
* public T read(JsonReader in) throws IOException {
|
|
||||||
* ++numReads;
|
|
||||||
* return delegate.read(in);
|
|
||||||
* }
|
|
||||||
* };
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* } </pre>
|
|
||||||
* This factory can now be used like this:
|
|
||||||
* <pre> {@code
|
|
||||||
* StatsTypeAdapterFactory stats = new StatsTypeAdapterFactory();
|
|
||||||
* Gson gson = new GsonBuilder().registerTypeAdapterFactory(stats).create();
|
|
||||||
* // Call gson.toJson() and fromJson methods on objects
|
|
||||||
* System.out.println("Num JSON reads" + stats.numReads);
|
|
||||||
* System.out.println("Num JSON writes" + stats.numWrites);
|
|
||||||
* }</pre>
|
|
||||||
* Note that this call will skip all factories registered before {@code skipPast}. In case of
|
|
||||||
* multiple TypeAdapterFactories registered it is up to the caller of this function to insure
|
|
||||||
* that the order of registration does not prevent this method from reaching a factory they
|
|
||||||
* would expect to reply from this call.
|
|
||||||
* Note that since you can not override type adapter factories for String and Java primitive
|
|
||||||
* types, our stats factory will not count the number of String or primitives that will be
|
|
||||||
* read or written.
|
|
||||||
* @param skipPast The type adapter factory that needs to be skipped while searching for
|
|
||||||
* a matching type adapter. In most cases, you should just pass <i>this</i> (the type adapter
|
|
||||||
* factory from where {@link #getDelegateAdapter} method is being invoked).
|
|
||||||
* @param type Type for which the delegate adapter is being searched for.
|
|
||||||
*
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) {
|
|
||||||
// Hack. If the skipPast factory isn't registered, assume the factory is being requested via
|
|
||||||
// our @JsonAdapter annotation.
|
|
||||||
if (!factories.contains(skipPast)) {
|
|
||||||
skipPast = jsonAdapterFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean skipPastFound = false;
|
|
||||||
for (TypeAdapterFactory factory : factories) {
|
|
||||||
if (!skipPastFound) {
|
|
||||||
if (factory == skipPast) {
|
|
||||||
skipPastFound = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeAdapter<T> candidate = factory.create(this, type);
|
|
||||||
if (candidate != null) {
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("GSON cannot serialize " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type adapter for {@code} type.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
|
||||||
* deserialize {@code type}.
|
|
||||||
*/
|
|
||||||
public <T> TypeAdapter<T> getAdapter(Class<T> type) {
|
|
||||||
return getAdapter(TypeToken.get(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.INSTANCE;
|
|
||||||
}
|
|
||||||
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 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) {
|
|
||||||
JsonTreeWriter writer = new JsonTreeWriter();
|
|
||||||
toJson(src, typeOfSrc, writer);
|
|
||||||
return writer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 toJson(JsonNull.INSTANCE);
|
|
||||||
}
|
|
||||||
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 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(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 {
|
|
||||||
if (src != null) {
|
|
||||||
toJson(src, src.getClass(), writer);
|
|
||||||
} else {
|
|
||||||
toJson(JsonNull.INSTANCE, writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 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 {
|
|
||||||
try {
|
|
||||||
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
|
|
||||||
toJson(src, typeOfSrc, jsonWriter);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
|
|
||||||
TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
|
|
||||||
boolean oldLenient = writer.isLenient();
|
|
||||||
writer.setLenient(true);
|
|
||||||
boolean oldHtmlSafe = writer.isHtmlSafe();
|
|
||||||
writer.setHtmlSafe(htmlSafe);
|
|
||||||
boolean oldSerializeNulls = writer.getSerializeNulls();
|
|
||||||
writer.setSerializeNulls(serializeNulls);
|
|
||||||
try {
|
|
||||||
((TypeAdapter<Object>) adapter).write(writer, src);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
} finally {
|
|
||||||
writer.setLenient(oldLenient);
|
|
||||||
writer.setHtmlSafe(oldHtmlSafe);
|
|
||||||
writer.setSerializeNulls(oldSerializeNulls);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 {
|
|
||||||
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
|
|
||||||
toJson(jsonElement, jsonWriter);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new JSON writer configured for the settings on this Gson instance.
|
|
||||||
*/
|
|
||||||
public JsonWriter newJsonWriter(Writer writer) throws IOException {
|
|
||||||
if (generateNonExecutableJson) {
|
|
||||||
writer.write(JSON_NON_EXECUTABLE_PREFIX);
|
|
||||||
}
|
|
||||||
JsonWriter jsonWriter = new JsonWriter(writer);
|
|
||||||
if (prettyPrinting) {
|
|
||||||
jsonWriter.setIndent(" ");
|
|
||||||
}
|
|
||||||
jsonWriter.setSerializeNulls(serializeNulls);
|
|
||||||
return jsonWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new JSON reader configured for the settings on this Gson instance.
|
|
||||||
*/
|
|
||||||
public JsonReader newJsonReader(Reader reader) {
|
|
||||||
JsonReader jsonReader = new JsonReader(reader);
|
|
||||||
jsonReader.setLenient(lenient);
|
|
||||||
return jsonReader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
boolean oldSerializeNulls = writer.getSerializeNulls();
|
|
||||||
writer.setSerializeNulls(serializeNulls);
|
|
||||||
try {
|
|
||||||
Streams.write(jsonElement, writer);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
} finally {
|
|
||||||
writer.setLenient(oldLenient);
|
|
||||||
writer.setHtmlSafe(oldHtmlSafe);
|
|
||||||
writer.setSerializeNulls(oldSerializeNulls);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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. Returns {@code null} if {@code json} is {@code null}.
|
|
||||||
* @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 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. Returns {@code null} if {@code json} is {@code null}.
|
|
||||||
* @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. Returns {@code null} if {@code json} is at EOF.
|
|
||||||
* @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 = newJsonReader(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 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. Returns {@code null} if {@code json} is at EOF.
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
|
||||||
JsonReader jsonReader = newJsonReader(json);
|
|
||||||
T object = (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}. Returns {@code null}, if the {@code reader} is at EOF.
|
|
||||||
* 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 isEmpty = true;
|
|
||||||
boolean oldLenient = reader.isLenient();
|
|
||||||
reader.setLenient(true);
|
|
||||||
try {
|
|
||||||
reader.peek();
|
|
||||||
isEmpty = false;
|
|
||||||
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
|
|
||||||
TypeAdapter<T> typeAdapter = getAdapter(typeToken);
|
|
||||||
T object = typeAdapter.read(reader);
|
|
||||||
return object;
|
|
||||||
} catch (EOFException e) {
|
|
||||||
/*
|
|
||||||
* For compatibility with JSON 1.5 and earlier, we return null for empty
|
|
||||||
* documents instead of throwing.
|
|
||||||
*/
|
|
||||||
if (isEmpty) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
} 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. Returns {@code null} if {@code json} is {@code null}.
|
|
||||||
* @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 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. Returns {@code null} if {@code json} is {@code null}.
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
return (T) fromJson(new JsonTreeReader(json), typeOfT);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class FutureTypeAdapter<T> extends TypeAdapter<T> {
|
|
||||||
private TypeAdapter<T> delegate;
|
|
||||||
|
|
||||||
public void setDelegate(TypeAdapter<T> typeAdapter) {
|
|
||||||
if (delegate != null) {
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
delegate = typeAdapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public T read(JsonReader in) throws IOException {
|
|
||||||
if (delegate == null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
return delegate.read(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void write(JsonWriter out, T value) throws IOException {
|
|
||||||
if (delegate == null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
delegate.write(out, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new StringBuilder("{serializeNulls:")
|
|
||||||
.append(serializeNulls)
|
|
||||||
.append("factories:").append(factories)
|
|
||||||
.append(",instanceCreators:").append(constructorConstructor)
|
|
||||||
.append("}")
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,578 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.annotations.Expose;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.Excluder;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.TreeTypeAdapter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.TypeAdapters;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <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())
|
|
||||||
* .enableComplexMapKeySerialization()
|
|
||||||
* .serializeNulls()
|
|
||||||
* .setDateFormat(DateFormat.LONG)
|
|
||||||
* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
|
|
||||||
* .setPrettyPrinting()
|
|
||||||
* .setVersion(1.0)
|
|
||||||
* .create();
|
|
||||||
* </pre></p>
|
|
||||||
*
|
|
||||||
* <p>NOTES:
|
|
||||||
* <ul>
|
|
||||||
* <li> the order of invocation of configuration methods does not matter.</li>
|
|
||||||
* <li> The default serialization of {@link Date} and its subclasses in Gson does
|
|
||||||
* not contain time-zone information. So, if you are using date/time instances,
|
|
||||||
* use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
* @author Jesse Wilson
|
|
||||||
*/
|
|
||||||
public final class GsonBuilder {
|
|
||||||
private Excluder excluder = Excluder.DEFAULT;
|
|
||||||
private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;
|
|
||||||
private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
|
|
||||||
private final Map<Type, InstanceCreator<?>> instanceCreators
|
|
||||||
= new HashMap<>();
|
|
||||||
private final List<TypeAdapterFactory> factories = new ArrayList<>();
|
|
||||||
/** tree-style hierarchy factories. These come after factories for backwards compatibility. */
|
|
||||||
private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<>();
|
|
||||||
private boolean serializeNulls = Gson.DEFAULT_SERIALIZE_NULLS;
|
|
||||||
private String datePattern;
|
|
||||||
private int dateStyle = DateFormat.DEFAULT;
|
|
||||||
private int timeStyle = DateFormat.DEFAULT;
|
|
||||||
private boolean complexMapKeySerialization = Gson.DEFAULT_COMPLEX_MAP_KEYS;
|
|
||||||
private boolean serializeSpecialFloatingPointValues = Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
|
|
||||||
private boolean escapeHtmlChars = Gson.DEFAULT_ESCAPE_HTML;
|
|
||||||
private boolean prettyPrinting = Gson.DEFAULT_PRETTY_PRINT;
|
|
||||||
private boolean generateNonExecutableJson = Gson.DEFAULT_JSON_NON_EXECUTABLE;
|
|
||||||
private boolean lenient = Gson.DEFAULT_LENIENT;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
excluder = excluder.withVersion(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) {
|
|
||||||
excluder = excluder.withModifiers(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 Expose} annotation.
|
|
||||||
*
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
*/
|
|
||||||
public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
|
|
||||||
excluder = excluder.excludeFieldsWithoutExposeAnnotation();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enabling this feature will only change the serialized form if the map key is
|
|
||||||
* a complex type (i.e. non-primitive) in its <strong>serialized</strong> JSON
|
|
||||||
* form. The default implementation of map serialization uses {@code toString()}
|
|
||||||
* on the key; however, when this is called then one of the following cases
|
|
||||||
* apply:
|
|
||||||
*
|
|
||||||
* <h3>Maps as JSON objects</h3>
|
|
||||||
* For this case, assume that a type adapter is registered to serialize and
|
|
||||||
* deserialize some {@code Point} class, which contains an x and y coordinate,
|
|
||||||
* to/from the JSON Primitive string value {@code "(x,y)"}. The Java map would
|
|
||||||
* then be serialized as a {@link JsonObject}.
|
|
||||||
*
|
|
||||||
* <p>Below is an example:
|
|
||||||
* <pre> {@code
|
|
||||||
* Gson gson = new GsonBuilder()
|
|
||||||
* .register(Point.class, new MyPointTypeAdapter())
|
|
||||||
* .enableComplexMapKeySerialization()
|
|
||||||
* .create();
|
|
||||||
*
|
|
||||||
* 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>
|
|
||||||
*
|
|
||||||
* <h3>Maps as JSON arrays</h3>
|
|
||||||
* For this case, assume that a type adapter was NOT registered for some
|
|
||||||
* {@code Point} class, but rather the default Gson serialization is applied.
|
|
||||||
* In this case, some {@code new Point(2,3)} would serialize as {@code
|
|
||||||
* {"x":2,"y":5}}.
|
|
||||||
*
|
|
||||||
* <p>Given the assumption above, a {@code Map<Point, String>} will be
|
|
||||||
* serialize as an array of arrays (can be viewed as an entry set of pairs).
|
|
||||||
*
|
|
||||||
* <p>Below is an example of serializing complex types as JSON arrays:
|
|
||||||
* <pre> {@code
|
|
||||||
* Gson gson = new GsonBuilder()
|
|
||||||
* .enableComplexMapKeySerialization()
|
|
||||||
* .create();
|
|
||||||
*
|
|
||||||
* 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));
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* The JSON output would look as follows:
|
|
||||||
* <pre> {@code
|
|
||||||
* [
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* "x": 5,
|
|
||||||
* "y": 6
|
|
||||||
* },
|
|
||||||
* "a"
|
|
||||||
* ],
|
|
||||||
* [
|
|
||||||
* {
|
|
||||||
* "x": 8,
|
|
||||||
* "y": 8
|
|
||||||
* },
|
|
||||||
* "b"
|
|
||||||
* ]
|
|
||||||
* ]
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.7
|
|
||||||
*/
|
|
||||||
public GsonBuilder enableComplexMapKeySerialization() {
|
|
||||||
complexMapKeySerialization = 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() {
|
|
||||||
excluder = excluder.disableInnerClassSerialization();
|
|
||||||
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) {
|
|
||||||
this.fieldNamingPolicy = namingConvention;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
this.fieldNamingPolicy = 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 serialization/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) {
|
|
||||||
excluder = excluder.withExclusionStrategy(strategy, true, true);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Gson to apply the passed in exclusion strategy during serialization.
|
|
||||||
* If this method is invoked numerous times with different exclusion strategy objects
|
|
||||||
* then the exclusion strategies that were added will be applied as a disjunction rule.
|
|
||||||
* This means that if one of the added exclusion strategies suggests that a field (or
|
|
||||||
* class) should be skipped then that field (or object) is skipped during its
|
|
||||||
* serialization.
|
|
||||||
*
|
|
||||||
* @param strategy an exclusion strategy to apply during serialization.
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.7
|
|
||||||
*/
|
|
||||||
public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
|
|
||||||
excluder = excluder.withExclusionStrategy(strategy, true, false);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Gson to apply the passed in exclusion strategy during deserialization.
|
|
||||||
* If this method is invoked numerous times with different exclusion strategy objects
|
|
||||||
* then the exclusion strategies that were added will be applied as a disjunction rule.
|
|
||||||
* This means that if one of the added exclusion strategies suggests that a field (or
|
|
||||||
* class) should be skipped then that field (or object) is skipped during its
|
|
||||||
* deserialization.
|
|
||||||
*
|
|
||||||
* @param strategy an exclusion strategy to apply during deserialization.
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.7
|
|
||||||
*/
|
|
||||||
public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
|
|
||||||
excluder = excluder.withExclusionStrategy(strategy, false, true);
|
|
||||||
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 is strict and only accepts JSON as specified by
|
|
||||||
* <a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. This option makes the parser
|
|
||||||
* liberal in what it accepts.
|
|
||||||
*
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @see JsonReader#setLenient(boolean)
|
|
||||||
*/
|
|
||||||
public GsonBuilder setLenient() {
|
|
||||||
lenient = 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>The date format will be used to serialize and deserialize {@link java.util.Date}, {@link
|
|
||||||
* java.sql.Timestamp} and {@link java.sql.Date}.
|
|
||||||
*
|
|
||||||
* <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 TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a
|
|
||||||
* {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
|
|
||||||
* all the required interfaces for custom serialization with Gson. If a type adapter was
|
|
||||||
* previously registered for the specified {@code type}, it is overwritten.
|
|
||||||
*
|
|
||||||
* <p>This registers the type specified and no other types: you must manually register related
|
|
||||||
* types! For example, applications registering {@code boolean.class} should also register {@code
|
|
||||||
* Boolean.class}.
|
|
||||||
*
|
|
||||||
* @param type the type definition for the type adapter being registered
|
|
||||||
* @param typeAdapter This object must implement at least one of the {@link TypeAdapter},
|
|
||||||
* {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
|
|
||||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
|
||||||
|| typeAdapter instanceof JsonDeserializer<?>
|
|
||||||
|| typeAdapter instanceof InstanceCreator<?>
|
|
||||||
|| typeAdapter instanceof TypeAdapter<?>);
|
|
||||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
|
||||||
instanceCreators.put(type, (InstanceCreator) typeAdapter);
|
|
||||||
}
|
|
||||||
if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
|
|
||||||
TypeToken<?> typeToken = TypeToken.get(type);
|
|
||||||
factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
|
|
||||||
}
|
|
||||||
if (typeAdapter instanceof TypeAdapter<?>) {
|
|
||||||
factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a factory for type adapters. Registering a factory is useful when the type
|
|
||||||
* adapter needs to be configured based on the type of the field being processed. Gson
|
|
||||||
* is designed to handle a large number of factories, so you should consider registering
|
|
||||||
* them to be at par with registering an individual type adapter.
|
|
||||||
*
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) {
|
|
||||||
factories.add(factory);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
|
|
||||||
* This method combines the registration of a {@link TypeAdapter}, {@link JsonSerializer} and
|
|
||||||
* a {@link JsonDeserializer}. If a type adapter was previously registered for the specified
|
|
||||||
* type hierarchy, it is overridden. If a type adapter is registered for a specific type in
|
|
||||||
* the type hierarchy, it will be invoked instead of the one registered for the type hierarchy.
|
|
||||||
*
|
|
||||||
* @param baseType the class definition for the type adapter being registered for the base class
|
|
||||||
* or interface
|
|
||||||
* @param typeAdapter This object must implement at least one of {@link TypeAdapter},
|
|
||||||
* {@link JsonSerializer} or {@link JsonDeserializer} interfaces.
|
|
||||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
|
||||||
* @since 1.7
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
|
|
||||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
|
||||||
|| typeAdapter instanceof JsonDeserializer<?>
|
|
||||||
|| typeAdapter instanceof TypeAdapter<?>);
|
|
||||||
if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) {
|
|
||||||
hierarchyFactories.add(0,
|
|
||||||
TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter));
|
|
||||||
}
|
|
||||||
if (typeAdapter instanceof TypeAdapter<?>) {
|
|
||||||
factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter));
|
|
||||||
}
|
|
||||||
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<TypeAdapterFactory> factories = new ArrayList<>();
|
|
||||||
factories.addAll(this.factories);
|
|
||||||
Collections.reverse(factories);
|
|
||||||
factories.addAll(this.hierarchyFactories);
|
|
||||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);
|
|
||||||
|
|
||||||
return new Gson(excluder, fieldNamingPolicy, instanceCreators,
|
|
||||||
serializeNulls, complexMapKeySerialization,
|
|
||||||
generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
|
|
||||||
serializeSpecialFloatingPointValues, longSerializationPolicy, factories);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
|
|
||||||
List<TypeAdapterFactory> factories) {
|
|
||||||
DefaultDateTypeAdapter dateTypeAdapter;
|
|
||||||
if (datePattern != null && !"".equals(datePattern.trim())) {
|
|
||||||
dateTypeAdapter = new DefaultDateTypeAdapter(datePattern);
|
|
||||||
} else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
|
|
||||||
dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle);
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Date.class), dateTypeAdapter));
|
|
||||||
factories.add(TreeTypeAdapter.newFactory(TypeToken.get(Timestamp.class), dateTypeAdapter));
|
|
||||||
factories.add(TreeTypeAdapter.newFactory(TypeToken.get(java.sql.Date.class), dateTypeAdapter));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,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 com.massivecraft.massivecore.xlib.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,373 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
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<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
JsonArray deepCopy() {
|
|
||||||
JsonArray result = new JsonArray();
|
|
||||||
for (JsonElement element : elements) {
|
|
||||||
result.add(element.deepCopy());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the specified boolean to self.
|
|
||||||
*
|
|
||||||
* @param bool the boolean that needs to be added to the array.
|
|
||||||
*/
|
|
||||||
public void add(Boolean bool) {
|
|
||||||
elements.add(bool == null ? JsonNull.INSTANCE : new JsonPrimitive(bool));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the specified character to self.
|
|
||||||
*
|
|
||||||
* @param character the character that needs to be added to the array.
|
|
||||||
*/
|
|
||||||
public void add(Character character) {
|
|
||||||
elements.add(character == null ? JsonNull.INSTANCE : new JsonPrimitive(character));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the specified number to self.
|
|
||||||
*
|
|
||||||
* @param number the number that needs to be added to the array.
|
|
||||||
*/
|
|
||||||
public void add(Number number) {
|
|
||||||
elements.add(number == null ? JsonNull.INSTANCE : new JsonPrimitive(number));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the specified string to self.
|
|
||||||
*
|
|
||||||
* @param string the string that needs to be added to the array.
|
|
||||||
*/
|
|
||||||
public void add(String string) {
|
|
||||||
elements.add(string == null ? JsonNull.INSTANCE : new JsonPrimitive(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.INSTANCE;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces the element at the specified position in this array with the specified element.
|
|
||||||
* Element can be null.
|
|
||||||
* @param index index of the element to replace
|
|
||||||
* @param element element to be stored at the specified position
|
|
||||||
* @return the element previously at the specified position
|
|
||||||
* @throws IndexOutOfBoundsException if the specified index is outside the array bounds
|
|
||||||
*/
|
|
||||||
public JsonElement set(int index, JsonElement element) {
|
|
||||||
return elements.set(index, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the first occurrence of the specified element from this array, if it is present.
|
|
||||||
* If the array does not contain the element, it is unchanged.
|
|
||||||
* @param element element to be removed from this array, if present
|
|
||||||
* @return true if this array contained the specified element, false otherwise
|
|
||||||
* @since 2.3
|
|
||||||
*/
|
|
||||||
public boolean remove(JsonElement element) {
|
|
||||||
return elements.remove(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the element at the specified position in this array. Shifts any subsequent elements
|
|
||||||
* to the left (subtracts one from their indices). Returns the element that was removed from
|
|
||||||
* the array.
|
|
||||||
* @param index index the index of the element to be removed
|
|
||||||
* @return the element previously at the specified position
|
|
||||||
* @throws IndexOutOfBoundsException if the specified index is outside the array bounds
|
|
||||||
* @since 2.3
|
|
||||||
*/
|
|
||||||
public JsonElement remove(int index) {
|
|
||||||
return elements.remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this array contains the specified element.
|
|
||||||
* @return true if this array contains the specified element.
|
|
||||||
* @param element whose presence in this array is to be tested
|
|
||||||
* @since 2.3
|
|
||||||
*/
|
|
||||||
public boolean contains(JsonElement element) {
|
|
||||||
return elements.contains(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 elements 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return elements.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 com.massivecraft.massivecore.xlib.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,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 com.massivecraft.massivecore.xlib.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 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
* throws JsonParseException {
|
|
||||||
* return 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>
|
|
||||||
*
|
|
||||||
* <p>New applications should prefer {@link TypeAdapter}, whose streaming API
|
|
||||||
* is more efficient than this interface's tree API.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*
|
|
||||||
* @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,331 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.Streams;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
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 {
|
|
||||||
/**
|
|
||||||
* Returns a deep copy of this element. Immutable elements like primitives
|
|
||||||
* and nulls are not copied.
|
|
||||||
*/
|
|
||||||
abstract JsonElement deepCopy();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 IllegalStateException} 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("Not a JSON Object: " + this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convenience method to get this element as a {@link JsonArray}. If the element is of some
|
|
||||||
* other type, a {@link IllegalStateException} 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 IllegalStateException} 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 IllegalStateException} 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(getClass().getSimpleName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a String representation of this element.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
try {
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
|
||||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
|
||||||
jsonWriter.setLenient(true);
|
|
||||||
Streams.write(this, jsonWriter);
|
|
||||||
return stringWriter.toString();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.massivecraft.massivecore.xlib.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,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class representing a Json {@code null} value.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
* @since 1.2
|
|
||||||
*/
|
|
||||||
public final class JsonNull extends JsonElement {
|
|
||||||
/**
|
|
||||||
* singleton for JsonNull
|
|
||||||
*
|
|
||||||
* @since 1.8
|
|
||||||
*/
|
|
||||||
public static final JsonNull INSTANCE = new JsonNull();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new JsonNull object.
|
|
||||||
* Deprecated since Gson version 1.8. Use {@link #INSTANCE} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public JsonNull() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
JsonNull deepCopy() {
|
|
||||||
return INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 this == other || other instanceof JsonNull;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,204 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.LinkedTreeMap;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
private final LinkedTreeMap<String, JsonElement> members =
|
|
||||||
new LinkedTreeMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
JsonObject deepCopy() {
|
|
||||||
JsonObject result = new JsonObject();
|
|
||||||
for (Map.Entry<String, JsonElement> entry : members.entrySet()) {
|
|
||||||
result.add(entry.getKey(), entry.getValue().deepCopy());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
if (value == null) {
|
|
||||||
value = JsonNull.INSTANCE;
|
|
||||||
}
|
|
||||||
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.INSTANCE : 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of key/value pairs in the object.
|
|
||||||
*
|
|
||||||
* @return the number of key/value pairs in the object.
|
|
||||||
*/
|
|
||||||
public int size() {
|
|
||||||
return members.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
return members.get(memberName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
return (o == this) || (o instanceof JsonObject
|
|
||||||
&& ((JsonObject) o).members.equals(members));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return members.hashCode();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 com.massivecraft.massivecore.xlib.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,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.Streams;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.MalformedJsonException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
} finally {
|
|
||||||
json.setLenient(lenient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,341 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.LazilyParsedNumber;
|
|
||||||
|
|
||||||
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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
JsonPrimitive deepCopy() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
$Gson$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}.
|
|
||||||
*/
|
|
||||||
@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.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean getAsBoolean() {
|
|
||||||
if (isBoolean()) {
|
|
||||||
return getAsBooleanWrapper().booleanValue();
|
|
||||||
} else {
|
|
||||||
// Check to see if the value as a String is "true" in any case.
|
|
||||||
return 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 NumberFormatException if the value contained is not a valid Number.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Number getAsNumber() {
|
|
||||||
return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
@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 NumberFormatException 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 NumberFormatException 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 NumberFormatException 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 NumberFormatException 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 NumberFormatException 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (value instanceof Number) {
|
|
||||||
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 (value instanceof Number && other.value instanceof Number) {
|
|
||||||
double a = getAsNumber().doubleValue();
|
|
||||||
// Java standard types other than double return true for two NaN. So, need
|
|
||||||
// special handling for double.
|
|
||||||
double b = other.getAsNumber().doubleValue();
|
|
||||||
return a == b || (Double.isNaN(a) && Double.isNaN(b));
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 com.massivecraft.massivecore.xlib.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,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.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 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 serialize(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>
|
|
||||||
*
|
|
||||||
* <p>New applications should prefer {@link TypeAdapter}, whose streaming API
|
|
||||||
* is more efficient than this interface's tree API.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*
|
|
||||||
* @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,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.Streams;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.MalformedJsonException;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 com.massivecraft.massivecore.xlib.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,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2009 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.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() {
|
|
||||||
@Override public JsonElement serialize(Long value) {
|
|
||||||
return new JsonPrimitive(value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serializes a long value as a quoted string. For example, assume an object has a long field
|
|
||||||
* named "f" then the serialized output would be:
|
|
||||||
* {@code {"f":"123"}}.
|
|
||||||
*/
|
|
||||||
STRING() {
|
|
||||||
@Override public JsonElement serialize(Long value) {
|
|
||||||
return new JsonPrimitive(String.valueOf(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 abstract JsonElement serialize(Long value);
|
|
||||||
}
|
|
@ -1,287 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.JsonTreeReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.JsonTreeWriter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts Java objects to and from JSON.
|
|
||||||
*
|
|
||||||
* <h3>Defining a type's JSON form</h3>
|
|
||||||
* By default Gson converts application classes to JSON using its built-in type
|
|
||||||
* adapters. If Gson's default JSON conversion isn't appropriate for a type,
|
|
||||||
* extend this class to customize the conversion. Here's an example of a type
|
|
||||||
* adapter for an (X,Y) coordinate point: <pre> {@code
|
|
||||||
*
|
|
||||||
* public class PointAdapter extends TypeAdapter<Point> {
|
|
||||||
* public Point read(JsonReader reader) throws IOException {
|
|
||||||
* if (reader.peek() == JsonToken.NULL) {
|
|
||||||
* reader.nextNull();
|
|
||||||
* return null;
|
|
||||||
* }
|
|
||||||
* String xy = reader.nextString();
|
|
||||||
* String[] parts = xy.split(",");
|
|
||||||
* int x = Integer.parseInt(parts[0]);
|
|
||||||
* int y = Integer.parseInt(parts[1]);
|
|
||||||
* return new Point(x, y);
|
|
||||||
* }
|
|
||||||
* public void write(JsonWriter writer, Point value) throws IOException {
|
|
||||||
* if (value == null) {
|
|
||||||
* writer.nullValue();
|
|
||||||
* return;
|
|
||||||
* }
|
|
||||||
* String xy = value.getX() + "," + value.getY();
|
|
||||||
* writer.value(xy);
|
|
||||||
* }
|
|
||||||
* }}</pre>
|
|
||||||
* With this type adapter installed, Gson will convert {@code Points} to JSON as
|
|
||||||
* strings like {@code "5,8"} rather than objects like {@code {"x":5,"y":8}}. In
|
|
||||||
* this case the type adapter binds a rich Java class to a compact JSON value.
|
|
||||||
*
|
|
||||||
* <p>The {@link #read(JsonReader) read()} method must read exactly one value
|
|
||||||
* and {@link #write(JsonWriter,Object) write()} must write exactly one value.
|
|
||||||
* For primitive types this is means readers should make exactly one call to
|
|
||||||
* {@code nextBoolean()}, {@code nextDouble()}, {@code nextInt()}, {@code
|
|
||||||
* nextLong()}, {@code nextString()} or {@code nextNull()}. Writers should make
|
|
||||||
* exactly one call to one of <code>value()</code> or <code>nullValue()</code>.
|
|
||||||
* For arrays, type adapters should start with a call to {@code beginArray()},
|
|
||||||
* convert all elements, and finish with a call to {@code endArray()}. For
|
|
||||||
* objects, they should start with {@code beginObject()}, convert the object,
|
|
||||||
* and finish with {@code endObject()}. Failing to convert a value or converting
|
|
||||||
* too many values may cause the application to crash.
|
|
||||||
*
|
|
||||||
* <p>Type adapters should be prepared to read null from the stream and write it
|
|
||||||
* to the stream. Alternatively, they should use {@link #nullSafe()} method while
|
|
||||||
* registering the type adapter with Gson. If your {@code Gson} instance
|
|
||||||
* has been configured to {@link GsonBuilder#serializeNulls()}, these nulls will be
|
|
||||||
* written to the final document. Otherwise the value (and the corresponding name
|
|
||||||
* when writing to a JSON object) will be omitted automatically. In either case
|
|
||||||
* your type adapter must handle null.
|
|
||||||
*
|
|
||||||
* <p>To use a custom type adapter with Gson, you must <i>register</i> it with a
|
|
||||||
* {@link GsonBuilder}: <pre> {@code
|
|
||||||
*
|
|
||||||
* GsonBuilder builder = new GsonBuilder();
|
|
||||||
* builder.registerTypeAdapter(Point.class, new PointAdapter());
|
|
||||||
* // if PointAdapter didn't check for nulls in its read/write methods, you should instead use
|
|
||||||
* // builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
|
|
||||||
* ...
|
|
||||||
* Gson gson = builder.create();
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
// non-Javadoc:
|
|
||||||
//
|
|
||||||
// <h3>JSON Conversion</h3>
|
|
||||||
// <p>A type adapter registered with Gson is automatically invoked while serializing
|
|
||||||
// or deserializing JSON. However, you can also use type adapters directly to serialize
|
|
||||||
// and deserialize JSON. Here is an example for deserialization: <pre> {@code
|
|
||||||
//
|
|
||||||
// String json = "{'origin':'0,0','points':['1,2','3,4']}";
|
|
||||||
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
|
|
||||||
// Graph graph = graphAdapter.fromJson(json);
|
|
||||||
// }</pre>
|
|
||||||
// And an example for serialization: <pre> {@code
|
|
||||||
//
|
|
||||||
// Graph graph = new Graph(...);
|
|
||||||
// TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
|
|
||||||
// String json = graphAdapter.toJson(graph);
|
|
||||||
// }</pre>
|
|
||||||
//
|
|
||||||
// <p>Type adapters are <strong>type-specific</strong>. For example, a {@code
|
|
||||||
// TypeAdapter<Date>} can convert {@code Date} instances to JSON and JSON to
|
|
||||||
// instances of {@code Date}, but cannot convert any other types.
|
|
||||||
//
|
|
||||||
public abstract class TypeAdapter<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes one JSON value (an array, object, string, number, boolean or null)
|
|
||||||
* for {@code value}.
|
|
||||||
*
|
|
||||||
* @param value the Java object to write. May be null.
|
|
||||||
*/
|
|
||||||
public abstract void write(JsonWriter out, T value) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts {@code value} to a JSON document and writes it to {@code out}.
|
|
||||||
* Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson}
|
|
||||||
* method, this write is strict. Create a {@link
|
|
||||||
* JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
|
|
||||||
* {@link #write(JsonWriter, Object)} for lenient
|
|
||||||
* writing.
|
|
||||||
*
|
|
||||||
* @param value the Java object to convert. May be null.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public final void toJson(Writer out, T value) throws IOException {
|
|
||||||
JsonWriter writer = new JsonWriter(out);
|
|
||||||
write(writer, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This wrapper method is used to make a type adapter null tolerant. In general, a
|
|
||||||
* type adapter is required to handle nulls in write and read methods. Here is how this
|
|
||||||
* is typically done:<br>
|
|
||||||
* <pre> {@code
|
|
||||||
*
|
|
||||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
|
|
||||||
* new TypeAdapter<Foo>() {
|
|
||||||
* public Foo read(JsonReader in) throws IOException {
|
|
||||||
* if (in.peek() == JsonToken.NULL) {
|
|
||||||
* in.nextNull();
|
|
||||||
* return null;
|
|
||||||
* }
|
|
||||||
* // read a Foo from in and return it
|
|
||||||
* }
|
|
||||||
* public void write(JsonWriter out, Foo src) throws IOException {
|
|
||||||
* if (src == null) {
|
|
||||||
* out.nullValue();
|
|
||||||
* return;
|
|
||||||
* }
|
|
||||||
* // write src as JSON to out
|
|
||||||
* }
|
|
||||||
* }).create();
|
|
||||||
* }</pre>
|
|
||||||
* You can avoid this boilerplate handling of nulls by wrapping your type adapter with
|
|
||||||
* this method. Here is how we will rewrite the above example:
|
|
||||||
* <pre> {@code
|
|
||||||
*
|
|
||||||
* Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
|
|
||||||
* new TypeAdapter<Foo>() {
|
|
||||||
* public Foo read(JsonReader in) throws IOException {
|
|
||||||
* // read a Foo from in and return it
|
|
||||||
* }
|
|
||||||
* public void write(JsonWriter out, Foo src) throws IOException {
|
|
||||||
* // write src as JSON to out
|
|
||||||
* }
|
|
||||||
* }.nullSafe()).create();
|
|
||||||
* }</pre>
|
|
||||||
* Note that we didn't need to check for nulls in our type adapter after we used nullSafe.
|
|
||||||
*/
|
|
||||||
public final TypeAdapter<T> nullSafe() {
|
|
||||||
return new TypeAdapter<T>() {
|
|
||||||
@Override public void write(JsonWriter out, T value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
out.nullValue();
|
|
||||||
} else {
|
|
||||||
TypeAdapter.this.write(out, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Override public T read(JsonReader reader) throws IOException {
|
|
||||||
if (reader.peek() == JsonToken.NULL) {
|
|
||||||
reader.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return TypeAdapter.this.read(reader);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts {@code value} to a JSON document. Unlike Gson's similar {@link
|
|
||||||
* Gson#toJson(Object) toJson} method, this write is strict. Create a {@link
|
|
||||||
* JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call
|
|
||||||
* {@link #write(JsonWriter, Object)} for lenient
|
|
||||||
* writing.
|
|
||||||
*
|
|
||||||
* @param value the Java object to convert. May be null.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public final String toJson(T value) {
|
|
||||||
StringWriter stringWriter = new StringWriter();
|
|
||||||
try {
|
|
||||||
toJson(stringWriter, value);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError(e); // No I/O writing to a StringWriter.
|
|
||||||
}
|
|
||||||
return stringWriter.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts {@code value} to a JSON tree.
|
|
||||||
*
|
|
||||||
* @param value the Java object to convert. May be null.
|
|
||||||
* @return the converted JSON tree. May be {@link JsonNull}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public final JsonElement toJsonTree(T value) {
|
|
||||||
try {
|
|
||||||
JsonTreeWriter jsonWriter = new JsonTreeWriter();
|
|
||||||
write(jsonWriter, value);
|
|
||||||
return jsonWriter.get();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads one JSON value (an array, object, string, number, boolean or null)
|
|
||||||
* and converts it to a Java object. Returns the converted object.
|
|
||||||
*
|
|
||||||
* @return the converted Java object. May be null.
|
|
||||||
*/
|
|
||||||
public abstract T read(JsonReader in) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the JSON document in {@code in} to a Java object. Unlike Gson's
|
|
||||||
* similar {@link Gson#fromJson(java.io.Reader, Class) fromJson} method, this
|
|
||||||
* read is strict. Create a {@link JsonReader#setLenient(boolean) lenient}
|
|
||||||
* {@code JsonReader} and call {@link #read(JsonReader)} for lenient reading.
|
|
||||||
*
|
|
||||||
* @return the converted Java object. May be null.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public final T fromJson(Reader in) throws IOException {
|
|
||||||
JsonReader reader = new JsonReader(in);
|
|
||||||
return read(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the JSON document in {@code json} to a Java object. Unlike Gson's
|
|
||||||
* similar {@link Gson#fromJson(String, Class) fromJson} method, this read is
|
|
||||||
* strict. Create a {@link JsonReader#setLenient(boolean) lenient} {@code
|
|
||||||
* JsonReader} and call {@link #read(JsonReader)} for lenient reading.
|
|
||||||
*
|
|
||||||
* @return the converted Java object. May be null.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public final T fromJson(String json) throws IOException {
|
|
||||||
return fromJson(new StringReader(json));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts {@code jsonTree} to a Java object.
|
|
||||||
*
|
|
||||||
* @param jsonTree the Java object to convert. May be {@link JsonNull}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public final T fromJsonTree(JsonElement jsonTree) {
|
|
||||||
try {
|
|
||||||
JsonReader jsonReader = new JsonTreeReader(jsonTree);
|
|
||||||
return read(jsonReader);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates type adapters for set of related types. Type adapter factories are
|
|
||||||
* most useful when several types share similar structure in their JSON form.
|
|
||||||
*
|
|
||||||
* <h3>Example: Converting enums to lowercase</h3>
|
|
||||||
* In this example, we implement a factory that creates type adapters for all
|
|
||||||
* enums. The type adapters will write enums in lowercase, despite the fact
|
|
||||||
* that they're defined in {@code CONSTANT_CASE} in the corresponding Java
|
|
||||||
* model: <pre> {@code
|
|
||||||
*
|
|
||||||
* public class LowercaseEnumTypeAdapterFactory implements TypeAdapterFactory {
|
|
||||||
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
|
||||||
* Class<T> rawType = (Class<T>) type.getRawType();
|
|
||||||
* if (!rawType.isEnum()) {
|
|
||||||
* return null;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* final Map<String, T> lowercaseToConstant = new HashMap<String, T>();
|
|
||||||
* for (T constant : rawType.getEnumConstants()) {
|
|
||||||
* lowercaseToConstant.put(toLowercase(constant), constant);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* return new TypeAdapter<T>() {
|
|
||||||
* public void write(JsonWriter out, T value) throws IOException {
|
|
||||||
* if (value == null) {
|
|
||||||
* out.nullValue();
|
|
||||||
* } else {
|
|
||||||
* out.value(toLowercase(value));
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public T read(JsonReader reader) throws IOException {
|
|
||||||
* if (reader.peek() == JsonToken.NULL) {
|
|
||||||
* reader.nextNull();
|
|
||||||
* return null;
|
|
||||||
* } else {
|
|
||||||
* return lowercaseToConstant.get(reader.nextString());
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* };
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* private String toLowercase(Object o) {
|
|
||||||
* return o.toString().toLowerCase(Locale.US);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }</pre>
|
|
||||||
*
|
|
||||||
* <p>Type adapter factories select which types they provide type adapters
|
|
||||||
* for. If a factory cannot support a given type, it must return null when
|
|
||||||
* that type is passed to {@link #create}. Factories should expect {@code
|
|
||||||
* create()} to be called on them for many types and should return null for
|
|
||||||
* most of those types. In the above example the factory returns null for
|
|
||||||
* calls to {@code create()} where {@code type} is not an enum.
|
|
||||||
*
|
|
||||||
* <p>A factory is typically called once per type, but the returned type
|
|
||||||
* adapter may be used many times. It is most efficient to do expensive work
|
|
||||||
* like reflection in {@code create()} so that the type adapter's {@code
|
|
||||||
* read()} and {@code write()} methods can be very fast. In this example the
|
|
||||||
* mapping from lowercase name to enum value is computed eagerly.
|
|
||||||
*
|
|
||||||
* <p>As with type adapters, factories must be <i>registered</i> with a {@link
|
|
||||||
* GsonBuilder} for them to take effect: <pre> {@code
|
|
||||||
*
|
|
||||||
* GsonBuilder builder = new GsonBuilder();
|
|
||||||
* builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory());
|
|
||||||
* ...
|
|
||||||
* Gson gson = builder.create();
|
|
||||||
* }</pre>
|
|
||||||
* If multiple factories support the same type, the factory registered earlier
|
|
||||||
* takes precedence.
|
|
||||||
*
|
|
||||||
* <h3>Example: composing other type adapters</h3>
|
|
||||||
* In this example we implement a factory for Guava's {@code Multiset}
|
|
||||||
* collection type. The factory can be used to create type adapters for
|
|
||||||
* multisets of any element type: the type adapter for {@code
|
|
||||||
* Multiset<String>} is different from the type adapter for {@code
|
|
||||||
* Multiset<URL>}.
|
|
||||||
*
|
|
||||||
* <p>The type adapter <i>delegates</i> to another type adapter for the
|
|
||||||
* multiset elements. It figures out the element type by reflecting on the
|
|
||||||
* multiset's type token. A {@code Gson} is passed in to {@code create} for
|
|
||||||
* just this purpose: <pre> {@code
|
|
||||||
*
|
|
||||||
* public class MultisetTypeAdapterFactory implements TypeAdapterFactory {
|
|
||||||
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
|
||||||
* Type type = typeToken.getType();
|
|
||||||
* if (typeToken.getRawType() != Multiset.class
|
|
||||||
* || !(type instanceof ParameterizedType)) {
|
|
||||||
* return null;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
|
||||||
* TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
|
|
||||||
* return (TypeAdapter<T>) newMultisetAdapter(elementAdapter);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* private <E> TypeAdapter<Multiset<E>> newMultisetAdapter(
|
|
||||||
* final TypeAdapter<E> elementAdapter) {
|
|
||||||
* return new TypeAdapter<Multiset<E>>() {
|
|
||||||
* public void write(JsonWriter out, Multiset<E> value) throws IOException {
|
|
||||||
* if (value == null) {
|
|
||||||
* out.nullValue();
|
|
||||||
* return;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* out.beginArray();
|
|
||||||
* for (Multiset.Entry<E> entry : value.entrySet()) {
|
|
||||||
* out.value(entry.getCount());
|
|
||||||
* elementAdapter.write(out, entry.getElement());
|
|
||||||
* }
|
|
||||||
* out.endArray();
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public Multiset<E> read(JsonReader in) throws IOException {
|
|
||||||
* if (in.peek() == JsonToken.NULL) {
|
|
||||||
* in.nextNull();
|
|
||||||
* return null;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Multiset<E> result = LinkedHashMultiset.create();
|
|
||||||
* in.beginArray();
|
|
||||||
* while (in.hasNext()) {
|
|
||||||
* int count = in.nextInt();
|
|
||||||
* E element = elementAdapter.read(in);
|
|
||||||
* result.add(element, count);
|
|
||||||
* }
|
|
||||||
* in.endArray();
|
|
||||||
* return result;
|
|
||||||
* }
|
|
||||||
* };
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }</pre>
|
|
||||||
* Delegating from one type adapter to another is extremely powerful; it's
|
|
||||||
* the foundation of how Gson converts Java objects and collections. Whenever
|
|
||||||
* possible your factory should retrieve its delegate type adapter in the
|
|
||||||
* {@code create()} method; this ensures potentially-expensive type adapter
|
|
||||||
* creation happens only once.
|
|
||||||
*
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
public interface TypeAdapterFactory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a type adapter for {@code type}, or null if this factory doesn't
|
|
||||||
* support {@code type}.
|
|
||||||
*/
|
|
||||||
<T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.annotations;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An annotation that indicates this member should be exposed for JSON
|
|
||||||
* serialization or deserialization.
|
|
||||||
*
|
|
||||||
* <p>This annotation has no effect unless you build {@link Gson}
|
|
||||||
* with a {@link GsonBuilder} and invoke
|
|
||||||
* {@link 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
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@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,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.annotations;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory;
|
|
||||||
|
|
||||||
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 Gson {@link TypeAdapter} to use with a class
|
|
||||||
* or field.
|
|
||||||
*
|
|
||||||
* <p>Here is an example of how this annotation is used:</p>
|
|
||||||
* <pre>
|
|
||||||
* @JsonAdapter(UserJsonAdapter.class)
|
|
||||||
* public class User {
|
|
||||||
* public final String firstName, lastName;
|
|
||||||
* private User(String firstName, String lastName) {
|
|
||||||
* this.firstName = firstName;
|
|
||||||
* this.lastName = lastName;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* public class UserJsonAdapter extends TypeAdapter<User> {
|
|
||||||
* @Override public void write(JsonWriter out, User user) throws IOException {
|
|
||||||
* // implement write: combine firstName and lastName into name
|
|
||||||
* out.beginObject();
|
|
||||||
* out.name("name");
|
|
||||||
* out.value(user.firstName + " " + user.lastName);
|
|
||||||
* out.endObject();
|
|
||||||
* // implement the write method
|
|
||||||
* }
|
|
||||||
* @Override public User read(JsonReader in) throws IOException {
|
|
||||||
* // implement read: split name into firstName and lastName
|
|
||||||
* in.beginObject();
|
|
||||||
* in.nextName();
|
|
||||||
* String[] nameParts = in.nextString().split(" ");
|
|
||||||
* in.endObject();
|
|
||||||
* return new User(nameParts[0], nameParts[1]);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* Since User class specified UserJsonAdapter.class in @JsonAdapter annotation, it
|
|
||||||
* will automatically be invoked to serialize/deserialize User instances. <br>
|
|
||||||
*
|
|
||||||
* <p> Here is an example of how to apply this annotation to a field.
|
|
||||||
* <pre>
|
|
||||||
* private static final class Gadget {
|
|
||||||
* @JsonAdapter(UserJsonAdapter2.class)
|
|
||||||
* final User user;
|
|
||||||
* Gadget(User user) {
|
|
||||||
* this.user = user;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* It's possible to specify different type adapters on a field, that
|
|
||||||
* field's type, and in the {@link GsonBuilder}. Field
|
|
||||||
* annotations take precedence over {@code GsonBuilder}-registered type
|
|
||||||
* adapters, which in turn take precedence over annotated types.
|
|
||||||
*
|
|
||||||
* <p>The class referenced by this annotation must be either a {@link
|
|
||||||
* TypeAdapter} or a {@link TypeAdapterFactory}. Using the factory interface
|
|
||||||
* makes it possible to delegate to the enclosing {@code Gson} instance.
|
|
||||||
*
|
|
||||||
* @since 2.3
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
* @author Jesse Wilson
|
|
||||||
*/
|
|
||||||
// Note that the above example is taken from AdaptAnnotationTest.
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
|
||||||
public @interface JsonAdapter {
|
|
||||||
|
|
||||||
/** Either a {@link TypeAdapter} or {@link TypeAdapterFactory}. */
|
|
||||||
Class<?> value();
|
|
||||||
|
|
||||||
/** false, to be able to handle {@code null} values within the adapter, default value is true. */
|
|
||||||
boolean nullSafe() default true;
|
|
||||||
|
|
||||||
}
|
|
@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.annotations;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.FieldNamingPolicy;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 FieldNamingPolicy}, including
|
|
||||||
* the default field naming policy, that may have been set on the {@link Gson}
|
|
||||||
* instance. A different naming policy can set using the {@code GsonBuilder} class. See
|
|
||||||
* {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}
|
|
||||||
* for more information.</p>
|
|
||||||
*
|
|
||||||
* <p>Here is an example of how this annotation is meant to be used:</p>
|
|
||||||
* <pre>
|
|
||||||
* public class MyClass {
|
|
||||||
* @SerializedName("name") String a;
|
|
||||||
* @SerializedName(value="name1", alternate={"name2", "name3"}) String b;
|
|
||||||
* String c;
|
|
||||||
*
|
|
||||||
* public MyClass(String a, String b, String c) {
|
|
||||||
* this.a = a;
|
|
||||||
* this.b = b;
|
|
||||||
* this.c = c;
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>The following shows the output that is generated when serializing an instance of the
|
|
||||||
* above example class:</p>
|
|
||||||
* <pre>
|
|
||||||
* MyClass target = new MyClass("v1", "v2", "v3");
|
|
||||||
* Gson gson = new Gson();
|
|
||||||
* String json = gson.toJson(target);
|
|
||||||
* System.out.println(json);
|
|
||||||
*
|
|
||||||
* ===== OUTPUT =====
|
|
||||||
* {"name":"v1","name1":"v2","c":"v3"}
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p>
|
|
||||||
* While deserializing, all values specified in the annotation will be deserialized into the field.
|
|
||||||
* For example:
|
|
||||||
* <pre>
|
|
||||||
* MyClass target = gson.fromJson("{'name1':'v1'}", MyClass.class);
|
|
||||||
* assertEquals("v1", target.b);
|
|
||||||
* target = gson.fromJson("{'name2':'v2'}", MyClass.class);
|
|
||||||
* assertEquals("v2", target.b);
|
|
||||||
* target = gson.fromJson("{'name3':'v3'}", MyClass.class);
|
|
||||||
* assertEquals("v3", target.b);
|
|
||||||
* </pre>
|
|
||||||
* Note that MyClass.b is now deserialized from either name1, name2 or name3.
|
|
||||||
*
|
|
||||||
* @see FieldNamingPolicy
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
* @author Joel Leitch
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
|
||||||
public @interface SerializedName {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the desired name of the field when it is serialized or deserialized
|
|
||||||
*/
|
|
||||||
String value();
|
|
||||||
/**
|
|
||||||
* @return the alternative names of the field when it is deserialized
|
|
||||||
*/
|
|
||||||
String[] alternate() default {};
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.annotations;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 Gson} with a
|
|
||||||
* {@link GsonBuilder} and invoke
|
|
||||||
* {@link 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
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@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,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 com.massivecraft.massivecore.xlib.gson.annotations;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 Gson} with a
|
|
||||||
* {@link GsonBuilder} and invoke
|
|
||||||
* {@link 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
|
|
||||||
*/
|
|
||||||
@Documented
|
|
||||||
@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 com.massivecraft.massivecore.xlib.gson.Gson}.
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh, Joel Leitch
|
|
||||||
*/
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.annotations;
|
|
@ -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 com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
public final class $Gson$Preconditions {
|
|
||||||
private $Gson$Preconditions() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> T checkNotNull(T obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkArgument(boolean condition) {
|
|
||||||
if (!condition) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,577 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.reflect.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions.checkArgument;
|
|
||||||
import static com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static methods for working with types.
|
|
||||||
*
|
|
||||||
* @author Bob Lee
|
|
||||||
* @author Jesse Wilson
|
|
||||||
*/
|
|
||||||
public final class $Gson$Types {
|
|
||||||
static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
|
|
||||||
|
|
||||||
private $Gson$Types() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new parameterized type, applying {@code typeArguments} to
|
|
||||||
* {@code rawType} and enclosed by {@code ownerType}.
|
|
||||||
*
|
|
||||||
* @return a {@link java.io.Serializable serializable} parameterized type.
|
|
||||||
*/
|
|
||||||
public static ParameterizedType newParameterizedTypeWithOwner(
|
|
||||||
Type ownerType, Type rawType, Type... typeArguments) {
|
|
||||||
return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array type whose elements are all instances of
|
|
||||||
* {@code componentType}.
|
|
||||||
*
|
|
||||||
* @return a {@link java.io.Serializable serializable} generic array type.
|
|
||||||
*/
|
|
||||||
public static GenericArrayType arrayOf(Type componentType) {
|
|
||||||
return new GenericArrayTypeImpl(componentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a type that represents an unknown type that extends {@code bound}.
|
|
||||||
* For example, if {@code bound} is {@code CharSequence.class}, this returns
|
|
||||||
* {@code ? extends CharSequence}. If {@code bound} is {@code Object.class},
|
|
||||||
* this returns {@code ?}, which is shorthand for {@code ? extends Object}.
|
|
||||||
*/
|
|
||||||
public static WildcardType subtypeOf(Type bound) {
|
|
||||||
return new WildcardTypeImpl(new Type[] { bound }, EMPTY_TYPE_ARRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a type that represents an unknown supertype of {@code bound}. For
|
|
||||||
* example, if {@code bound} is {@code String.class}, this returns {@code ?
|
|
||||||
* super String}.
|
|
||||||
*/
|
|
||||||
public static WildcardType supertypeOf(Type bound) {
|
|
||||||
return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a type that is functionally equal but not necessarily equal
|
|
||||||
* according to {@link Object#equals(Object) Object.equals()}. The returned
|
|
||||||
* type is {@link java.io.Serializable}.
|
|
||||||
*/
|
|
||||||
public static Type canonicalize(Type type) {
|
|
||||||
if (type instanceof Class) {
|
|
||||||
Class<?> c = (Class<?>) type;
|
|
||||||
return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
|
|
||||||
|
|
||||||
} else if (type instanceof ParameterizedType) {
|
|
||||||
ParameterizedType p = (ParameterizedType) type;
|
|
||||||
return new ParameterizedTypeImpl(p.getOwnerType(),
|
|
||||||
p.getRawType(), p.getActualTypeArguments());
|
|
||||||
|
|
||||||
} else if (type instanceof GenericArrayType) {
|
|
||||||
GenericArrayType g = (GenericArrayType) type;
|
|
||||||
return new GenericArrayTypeImpl(g.getGenericComponentType());
|
|
||||||
|
|
||||||
} else if (type instanceof WildcardType) {
|
|
||||||
WildcardType w = (WildcardType) type;
|
|
||||||
return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// type is either serializable as-is or unsupported
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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();
|
|
||||||
checkArgument(rawType instanceof Class);
|
|
||||||
return (Class<?>) rawType;
|
|
||||||
|
|
||||||
} else if (type instanceof GenericArrayType) {
|
|
||||||
Type componentType = ((GenericArrayType)type).getGenericComponentType();
|
|
||||||
return Array.newInstance(getRawType(componentType), 0).getClass();
|
|
||||||
|
|
||||||
} else if (type instanceof TypeVariable) {
|
|
||||||
// we could use the variable's bounds, but that won't work if there are multiple.
|
|
||||||
// having a raw type that's more general than necessary is okay
|
|
||||||
return Object.class;
|
|
||||||
|
|
||||||
} else if (type instanceof WildcardType) {
|
|
||||||
return getRawType(((WildcardType) type).getUpperBounds()[0]);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
String className = type == null ? "null" : type.getClass().getName();
|
|
||||||
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
|
|
||||||
+ "GenericArrayType, but <" + type + "> is of type " + className);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean equal(Object a, Object b) {
|
|
||||||
return a == b || (a != null && a.equals(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if {@code a} and {@code b} are equal.
|
|
||||||
*/
|
|
||||||
public static boolean equals(Type a, Type b) {
|
|
||||||
if (a == b) {
|
|
||||||
// also handles (a == null && b == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} else if (a instanceof Class) {
|
|
||||||
// Class already specifies equals().
|
|
||||||
return a.equals(b);
|
|
||||||
|
|
||||||
} else if (a instanceof ParameterizedType) {
|
|
||||||
if (!(b instanceof ParameterizedType)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: save a .clone() call
|
|
||||||
ParameterizedType pa = (ParameterizedType) a;
|
|
||||||
ParameterizedType pb = (ParameterizedType) b;
|
|
||||||
return equal(pa.getOwnerType(), pb.getOwnerType())
|
|
||||||
&& pa.getRawType().equals(pb.getRawType())
|
|
||||||
&& Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
|
|
||||||
|
|
||||||
} else if (a instanceof GenericArrayType) {
|
|
||||||
if (!(b instanceof GenericArrayType)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericArrayType ga = (GenericArrayType) a;
|
|
||||||
GenericArrayType gb = (GenericArrayType) b;
|
|
||||||
return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
|
|
||||||
|
|
||||||
} else if (a instanceof WildcardType) {
|
|
||||||
if (!(b instanceof WildcardType)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
WildcardType wa = (WildcardType) a;
|
|
||||||
WildcardType wb = (WildcardType) b;
|
|
||||||
return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())
|
|
||||||
&& Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());
|
|
||||||
|
|
||||||
} else if (a instanceof TypeVariable) {
|
|
||||||
if (!(b instanceof TypeVariable)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TypeVariable<?> va = (TypeVariable<?>) a;
|
|
||||||
TypeVariable<?> vb = (TypeVariable<?>) b;
|
|
||||||
return va.getGenericDeclaration() == vb.getGenericDeclaration()
|
|
||||||
&& va.getName().equals(vb.getName());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// This isn't a type we support. Could be a generic array type, wildcard type, etc.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hashCodeOrZero(Object o) {
|
|
||||||
return o != null ? o.hashCode() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String typeToString(Type type) {
|
|
||||||
return type instanceof Class ? ((Class<?>) type).getName() : type.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the generic supertype for {@code supertype}. For example, given a class {@code
|
|
||||||
* IntegerSet}, the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the
|
|
||||||
* result when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
|
|
||||||
*/
|
|
||||||
static Type getGenericSupertype(Type context, Class<?> rawType, Class<?> toResolve) {
|
|
||||||
if (toResolve == rawType) {
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we skip searching through interfaces if unknown is an interface
|
|
||||||
if (toResolve.isInterface()) {
|
|
||||||
Class<?>[] interfaces = rawType.getInterfaces();
|
|
||||||
for (int i = 0, length = interfaces.length; i < length; i++) {
|
|
||||||
if (interfaces[i] == toResolve) {
|
|
||||||
return rawType.getGenericInterfaces()[i];
|
|
||||||
} else if (toResolve.isAssignableFrom(interfaces[i])) {
|
|
||||||
return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check our supertypes
|
|
||||||
if (!rawType.isInterface()) {
|
|
||||||
while (rawType != Object.class) {
|
|
||||||
Class<?> rawSupertype = rawType.getSuperclass();
|
|
||||||
if (rawSupertype == toResolve) {
|
|
||||||
return rawType.getGenericSuperclass();
|
|
||||||
} else if (toResolve.isAssignableFrom(rawSupertype)) {
|
|
||||||
return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
|
|
||||||
}
|
|
||||||
rawType = rawSupertype;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we can't resolve this further
|
|
||||||
return toResolve;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the generic form of {@code supertype}. For example, if this is {@code
|
|
||||||
* ArrayList<String>}, this returns {@code Iterable<String>} given the input {@code
|
|
||||||
* Iterable.class}.
|
|
||||||
*
|
|
||||||
* @param supertype a superclass of, or interface implemented by, this.
|
|
||||||
*/
|
|
||||||
static Type getSupertype(Type context, Class<?> contextRawType, Class<?> supertype) {
|
|
||||||
checkArgument(supertype.isAssignableFrom(contextRawType));
|
|
||||||
return resolve(context, contextRawType,
|
|
||||||
$Gson$Types.getGenericSupertype(context, contextRawType, supertype));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the component type of this array type.
|
|
||||||
* @throws ClassCastException if this type is not an array.
|
|
||||||
*/
|
|
||||||
public static Type getArrayComponentType(Type array) {
|
|
||||||
return array instanceof GenericArrayType
|
|
||||||
? ((GenericArrayType) array).getGenericComponentType()
|
|
||||||
: ((Class<?>) array).getComponentType();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the element type of this collection type.
|
|
||||||
* @throws IllegalArgumentException if this type is not a collection.
|
|
||||||
*/
|
|
||||||
public static Type getCollectionElementType(Type context, Class<?> contextRawType) {
|
|
||||||
Type collectionType = getSupertype(context, contextRawType, Collection.class);
|
|
||||||
|
|
||||||
if (collectionType instanceof WildcardType) {
|
|
||||||
collectionType = ((WildcardType)collectionType).getUpperBounds()[0];
|
|
||||||
}
|
|
||||||
if (collectionType instanceof ParameterizedType) {
|
|
||||||
return ((ParameterizedType) collectionType).getActualTypeArguments()[0];
|
|
||||||
}
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a two element array containing this map's key and value types in
|
|
||||||
* positions 0 and 1 respectively.
|
|
||||||
*/
|
|
||||||
public static Type[] getMapKeyAndValueTypes(Type context, Class<?> contextRawType) {
|
|
||||||
/*
|
|
||||||
* Work around a problem with the declaration of java.util.Properties. That
|
|
||||||
* class should extend Hashtable<String, String>, but it's declared to
|
|
||||||
* extend Hashtable<Object, Object>.
|
|
||||||
*/
|
|
||||||
if (context == Properties.class) {
|
|
||||||
return new Type[] { String.class, String.class }; // TODO: test subclasses of Properties!
|
|
||||||
}
|
|
||||||
|
|
||||||
Type mapType = getSupertype(context, contextRawType, Map.class);
|
|
||||||
// TODO: strip wildcards?
|
|
||||||
if (mapType instanceof ParameterizedType) {
|
|
||||||
ParameterizedType mapParameterizedType = (ParameterizedType) mapType;
|
|
||||||
return mapParameterizedType.getActualTypeArguments();
|
|
||||||
}
|
|
||||||
return new Type[] { Object.class, Object.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type resolve(Type context, Class<?> contextRawType, Type toResolve) {
|
|
||||||
// this implementation is made a little more complicated in an attempt to avoid object-creation
|
|
||||||
while (true) {
|
|
||||||
if (toResolve instanceof TypeVariable) {
|
|
||||||
TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve;
|
|
||||||
toResolve = resolveTypeVariable(context, contextRawType, typeVariable);
|
|
||||||
if (toResolve == typeVariable) {
|
|
||||||
return toResolve;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) {
|
|
||||||
Class<?> original = (Class<?>) toResolve;
|
|
||||||
Type componentType = original.getComponentType();
|
|
||||||
Type newComponentType = resolve(context, contextRawType, componentType);
|
|
||||||
return componentType == newComponentType
|
|
||||||
? original
|
|
||||||
: arrayOf(newComponentType);
|
|
||||||
|
|
||||||
} else if (toResolve instanceof GenericArrayType) {
|
|
||||||
GenericArrayType original = (GenericArrayType) toResolve;
|
|
||||||
Type componentType = original.getGenericComponentType();
|
|
||||||
Type newComponentType = resolve(context, contextRawType, componentType);
|
|
||||||
return componentType == newComponentType
|
|
||||||
? original
|
|
||||||
: arrayOf(newComponentType);
|
|
||||||
|
|
||||||
} else if (toResolve instanceof ParameterizedType) {
|
|
||||||
ParameterizedType original = (ParameterizedType) toResolve;
|
|
||||||
Type ownerType = original.getOwnerType();
|
|
||||||
Type newOwnerType = resolve(context, contextRawType, ownerType);
|
|
||||||
boolean changed = newOwnerType != ownerType;
|
|
||||||
|
|
||||||
Type[] args = original.getActualTypeArguments();
|
|
||||||
for (int t = 0, length = args.length; t < length; t++) {
|
|
||||||
Type resolvedTypeArgument = resolve(context, contextRawType, args[t]);
|
|
||||||
if (resolvedTypeArgument != args[t]) {
|
|
||||||
if (!changed) {
|
|
||||||
args = args.clone();
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
args[t] = resolvedTypeArgument;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed
|
|
||||||
? newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args)
|
|
||||||
: original;
|
|
||||||
|
|
||||||
} else if (toResolve instanceof WildcardType) {
|
|
||||||
WildcardType original = (WildcardType) toResolve;
|
|
||||||
Type[] originalLowerBound = original.getLowerBounds();
|
|
||||||
Type[] originalUpperBound = original.getUpperBounds();
|
|
||||||
|
|
||||||
if (originalLowerBound.length == 1) {
|
|
||||||
Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]);
|
|
||||||
if (lowerBound != originalLowerBound[0]) {
|
|
||||||
return supertypeOf(lowerBound);
|
|
||||||
}
|
|
||||||
} else if (originalUpperBound.length == 1) {
|
|
||||||
Type upperBound = resolve(context, contextRawType, originalUpperBound[0]);
|
|
||||||
if (upperBound != originalUpperBound[0]) {
|
|
||||||
return subtypeOf(upperBound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return original;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return toResolve;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Type resolveTypeVariable(Type context, Class<?> contextRawType, TypeVariable<?> unknown) {
|
|
||||||
Class<?> declaredByRaw = declaringClassOf(unknown);
|
|
||||||
|
|
||||||
// we can't reduce this further
|
|
||||||
if (declaredByRaw == null) {
|
|
||||||
return unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw);
|
|
||||||
if (declaredBy instanceof ParameterizedType) {
|
|
||||||
int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
|
|
||||||
return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
return unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int indexOf(Object[] array, Object toFind) {
|
|
||||||
for (int i = 0; i < array.length; i++) {
|
|
||||||
if (toFind.equals(array[i])) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by
|
|
||||||
* a class.
|
|
||||||
*/
|
|
||||||
private static Class<?> declaringClassOf(TypeVariable<?> typeVariable) {
|
|
||||||
GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
|
|
||||||
return genericDeclaration instanceof Class
|
|
||||||
? (Class<?>) genericDeclaration
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void checkNotPrimitive(Type type) {
|
|
||||||
checkArgument(!(type instanceof Class<?>) || !((Class<?>) type).isPrimitive());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable {
|
|
||||||
private final Type ownerType;
|
|
||||||
private final Type rawType;
|
|
||||||
private final Type[] typeArguments;
|
|
||||||
|
|
||||||
public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
|
|
||||||
// require an owner type if the raw type needs it
|
|
||||||
if (rawType instanceof Class<?>) {
|
|
||||||
Class<?> rawTypeAsClass = (Class<?>) rawType;
|
|
||||||
boolean isStaticOrTopLevelClass = Modifier.isStatic(rawTypeAsClass.getModifiers())
|
|
||||||
|| rawTypeAsClass.getEnclosingClass() == null;
|
|
||||||
checkArgument(ownerType != null || isStaticOrTopLevelClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ownerType = ownerType == null ? null : canonicalize(ownerType);
|
|
||||||
this.rawType = canonicalize(rawType);
|
|
||||||
this.typeArguments = typeArguments.clone();
|
|
||||||
for (int t = 0; t < this.typeArguments.length; t++) {
|
|
||||||
checkNotNull(this.typeArguments[t]);
|
|
||||||
checkNotPrimitive(this.typeArguments[t]);
|
|
||||||
this.typeArguments[t] = canonicalize(this.typeArguments[t]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type[] getActualTypeArguments() {
|
|
||||||
return typeArguments.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getRawType() {
|
|
||||||
return rawType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getOwnerType() {
|
|
||||||
return ownerType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean equals(Object other) {
|
|
||||||
return other instanceof ParameterizedType
|
|
||||||
&& $Gson$Types.equals(this, (ParameterizedType) other);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode() {
|
|
||||||
return Arrays.hashCode(typeArguments)
|
|
||||||
^ rawType.hashCode()
|
|
||||||
^ hashCodeOrZero(ownerType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
|
|
||||||
stringBuilder.append(typeToString(rawType));
|
|
||||||
|
|
||||||
if (typeArguments.length == 0) {
|
|
||||||
return stringBuilder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
stringBuilder.append("<").append(typeToString(typeArguments[0]));
|
|
||||||
for (int i = 1; i < typeArguments.length; i++) {
|
|
||||||
stringBuilder.append(", ").append(typeToString(typeArguments[i]));
|
|
||||||
}
|
|
||||||
return stringBuilder.append(">").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class GenericArrayTypeImpl implements GenericArrayType, Serializable {
|
|
||||||
private final Type componentType;
|
|
||||||
|
|
||||||
public GenericArrayTypeImpl(Type componentType) {
|
|
||||||
this.componentType = canonicalize(componentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getGenericComponentType() {
|
|
||||||
return componentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean equals(Object o) {
|
|
||||||
return o instanceof GenericArrayType
|
|
||||||
&& $Gson$Types.equals(this, (GenericArrayType) o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode() {
|
|
||||||
return componentType.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return typeToString(componentType) + "[]";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The WildcardType interface supports multiple upper bounds and multiple
|
|
||||||
* lower bounds. We only support what the Java 6 language needs - at most one
|
|
||||||
* bound. If a lower bound is set, the upper bound must be Object.class.
|
|
||||||
*/
|
|
||||||
private static final class WildcardTypeImpl implements WildcardType, Serializable {
|
|
||||||
private final Type upperBound;
|
|
||||||
private final Type lowerBound;
|
|
||||||
|
|
||||||
public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
|
|
||||||
checkArgument(lowerBounds.length <= 1);
|
|
||||||
checkArgument(upperBounds.length == 1);
|
|
||||||
|
|
||||||
if (lowerBounds.length == 1) {
|
|
||||||
checkNotNull(lowerBounds[0]);
|
|
||||||
checkNotPrimitive(lowerBounds[0]);
|
|
||||||
checkArgument(upperBounds[0] == Object.class);
|
|
||||||
this.lowerBound = canonicalize(lowerBounds[0]);
|
|
||||||
this.upperBound = Object.class;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
checkNotNull(upperBounds[0]);
|
|
||||||
checkNotPrimitive(upperBounds[0]);
|
|
||||||
this.lowerBound = null;
|
|
||||||
this.upperBound = canonicalize(upperBounds[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type[] getUpperBounds() {
|
|
||||||
return new Type[] { upperBound };
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type[] getLowerBounds() {
|
|
||||||
return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean equals(Object other) {
|
|
||||||
return other instanceof WildcardType
|
|
||||||
&& $Gson$Types.equals(this, (WildcardType) other);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode() {
|
|
||||||
// this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
|
|
||||||
return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
|
|
||||||
^ (31 + upperBound.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
if (lowerBound != null) {
|
|
||||||
return "? super " + typeToString(lowerBound);
|
|
||||||
} else if (upperBound == Object.class) {
|
|
||||||
return "?";
|
|
||||||
} else {
|
|
||||||
return "? extends " + typeToString(upperBound);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,224 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.InstanceCreator;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.JsonIOException;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.concurrent.ConcurrentNavigableMap;
|
|
||||||
import java.util.concurrent.ConcurrentSkipListMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a function that can construct an instance of a requested type.
|
|
||||||
*/
|
|
||||||
public final class ConstructorConstructor {
|
|
||||||
private final Map<Type, InstanceCreator<?>> instanceCreators;
|
|
||||||
|
|
||||||
public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {
|
|
||||||
this.instanceCreators = instanceCreators;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
|
|
||||||
final Type type = typeToken.getType();
|
|
||||||
final Class<? super T> rawType = typeToken.getRawType();
|
|
||||||
|
|
||||||
// first try an instance creator
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") // types must agree
|
|
||||||
final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
|
|
||||||
if (typeCreator != null) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return typeCreator.createInstance(type);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next try raw type match for instance creators
|
|
||||||
@SuppressWarnings("unchecked") // types must agree
|
|
||||||
final InstanceCreator<T> rawTypeCreator =
|
|
||||||
(InstanceCreator<T>) instanceCreators.get(rawType);
|
|
||||||
if (rawTypeCreator != null) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return rawTypeCreator.createInstance(type);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
|
|
||||||
if (defaultConstructor != null) {
|
|
||||||
return defaultConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
|
|
||||||
if (defaultImplementation != null) {
|
|
||||||
return defaultImplementation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally try unsafe
|
|
||||||
return newUnsafeAllocator(type, rawType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
|
|
||||||
try {
|
|
||||||
final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
|
|
||||||
if (!constructor.isAccessible()) {
|
|
||||||
constructor.setAccessible(true);
|
|
||||||
}
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@SuppressWarnings("unchecked") // T is the same raw type as is requested
|
|
||||||
@Override public T construct() {
|
|
||||||
try {
|
|
||||||
Object[] args = null;
|
|
||||||
return (T) constructor.newInstance(args);
|
|
||||||
} catch (InstantiationException e) {
|
|
||||||
// TODO: JsonParseException ?
|
|
||||||
throw new RuntimeException("Failed to invoke " + constructor + " with no args", e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
// TODO: don't wrap if cause is unchecked!
|
|
||||||
// TODO: JsonParseException ?
|
|
||||||
throw new RuntimeException("Failed to invoke " + constructor + " with no args",
|
|
||||||
e.getTargetException());
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructors for common interface types like Map and List and their
|
|
||||||
* subtypes.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is
|
|
||||||
private <T> ObjectConstructor<T> newDefaultImplementationConstructor(
|
|
||||||
final Type type, Class<? super T> rawType) {
|
|
||||||
if (Collection.class.isAssignableFrom(rawType)) {
|
|
||||||
if (SortedSet.class.isAssignableFrom(rawType)) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new TreeSet<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if (EnumSet.class.isAssignableFrom(rawType)) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
@Override public T construct() {
|
|
||||||
if (type instanceof ParameterizedType) {
|
|
||||||
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
|
||||||
if (elementType instanceof Class) {
|
|
||||||
return (T) EnumSet.noneOf((Class)elementType);
|
|
||||||
} else {
|
|
||||||
throw new JsonIOException("Invalid EnumSet type: " + type.toString());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new JsonIOException("Invalid EnumSet type: " + type.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if (Set.class.isAssignableFrom(rawType)) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new LinkedHashSet<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if (Queue.class.isAssignableFrom(rawType)) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new ArrayDeque<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new ArrayList<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Map.class.isAssignableFrom(rawType)) {
|
|
||||||
if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new ConcurrentSkipListMap<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if (ConcurrentMap.class.isAssignableFrom(rawType)) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if (SortedMap.class.isAssignableFrom(rawType)) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new TreeMap<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else if (type instanceof ParameterizedType && !(String.class.isAssignableFrom(
|
|
||||||
TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType()))) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new LinkedHashMap<>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
@Override public T construct() {
|
|
||||||
return (T) new LinkedTreeMap<String, Object>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> ObjectConstructor<T> newUnsafeAllocator(
|
|
||||||
final Type type, final Class<? super T> rawType) {
|
|
||||||
return new ObjectConstructor<T>() {
|
|
||||||
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override public T construct() {
|
|
||||||
try {
|
|
||||||
Object newInstance = unsafeAllocator.newInstance(rawType);
|
|
||||||
return (T) newInstance;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
|
|
||||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return instanceCreators.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,248 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.*;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.annotations.Expose;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.annotations.Since;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.annotations.Until;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class selects which fields and types to omit. It is configurable,
|
|
||||||
* supporting version attributes {@link Since} and {@link Until}, modifiers,
|
|
||||||
* synthetic fields, anonymous and local classes, inner classes, and fields with
|
|
||||||
* the {@link Expose} annotation.
|
|
||||||
*
|
|
||||||
* <p>This class is a type adapter factory; types that are excluded will be
|
|
||||||
* adapted to null. It may delegate to another type adapter if only one
|
|
||||||
* direction is excluded.
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
* @author Jesse Wilson
|
|
||||||
*/
|
|
||||||
public final class Excluder implements TypeAdapterFactory, Cloneable {
|
|
||||||
private static final double IGNORE_VERSIONS = -1.0d;
|
|
||||||
public static final Excluder DEFAULT = new Excluder();
|
|
||||||
|
|
||||||
private double version = IGNORE_VERSIONS;
|
|
||||||
private int modifiers = Modifier.TRANSIENT | Modifier.STATIC;
|
|
||||||
private boolean serializeInnerClasses = true;
|
|
||||||
private boolean requireExpose;
|
|
||||||
private List<ExclusionStrategy> serializationStrategies = Collections.emptyList();
|
|
||||||
private List<ExclusionStrategy> deserializationStrategies = Collections.emptyList();
|
|
||||||
|
|
||||||
@Override protected Excluder clone() {
|
|
||||||
try {
|
|
||||||
return (Excluder) super.clone();
|
|
||||||
} catch (CloneNotSupportedException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Excluder withVersion(double ignoreVersionsAfter) {
|
|
||||||
Excluder result = clone();
|
|
||||||
result.version = ignoreVersionsAfter;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Excluder withModifiers(int... modifiers) {
|
|
||||||
Excluder result = clone();
|
|
||||||
result.modifiers = 0;
|
|
||||||
for (int modifier : modifiers) {
|
|
||||||
result.modifiers |= modifier;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Excluder disableInnerClassSerialization() {
|
|
||||||
Excluder result = clone();
|
|
||||||
result.serializeInnerClasses = false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Excluder excludeFieldsWithoutExposeAnnotation() {
|
|
||||||
Excluder result = clone();
|
|
||||||
result.requireExpose = true;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Excluder withExclusionStrategy(ExclusionStrategy exclusionStrategy,
|
|
||||||
boolean serialization, boolean deserialization) {
|
|
||||||
Excluder result = clone();
|
|
||||||
if (serialization) {
|
|
||||||
result.serializationStrategies = new ArrayList<>(serializationStrategies);
|
|
||||||
result.serializationStrategies.add(exclusionStrategy);
|
|
||||||
}
|
|
||||||
if (deserialization) {
|
|
||||||
result.deserializationStrategies
|
|
||||||
= new ArrayList<>(deserializationStrategies);
|
|
||||||
result.deserializationStrategies.add(exclusionStrategy);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
|
|
||||||
Class<?> rawType = type.getRawType();
|
|
||||||
final boolean skipSerialize = excludeClass(rawType, true);
|
|
||||||
final boolean skipDeserialize = excludeClass(rawType, false);
|
|
||||||
|
|
||||||
if (!skipSerialize && !skipDeserialize) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new TypeAdapter<T>() {
|
|
||||||
/** The delegate is lazily created because it may not be needed, and creating it may fail. */
|
|
||||||
private TypeAdapter<T> delegate;
|
|
||||||
|
|
||||||
@Override public T read(JsonReader in) throws IOException {
|
|
||||||
if (skipDeserialize) {
|
|
||||||
in.skipValue();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return delegate().read(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void write(JsonWriter out, T value) throws IOException {
|
|
||||||
if (skipSerialize) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
delegate().write(out, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeAdapter<T> delegate() {
|
|
||||||
TypeAdapter<T> d = delegate;
|
|
||||||
return d != null
|
|
||||||
? d
|
|
||||||
: (delegate = gson.getDelegateAdapter(Excluder.this, type));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean excludeField(Field field, boolean serialize) {
|
|
||||||
if ((modifiers & field.getModifiers()) != 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version != Excluder.IGNORE_VERSIONS
|
|
||||||
&& !isValidVersion(field.getAnnotation(Since.class), field.getAnnotation(Until.class))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.isSynthetic()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requireExpose) {
|
|
||||||
Expose annotation = field.getAnnotation(Expose.class);
|
|
||||||
if (annotation == null || (serialize ? !annotation.serialize() : !annotation.deserialize())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serializeInnerClasses && isInnerClass(field.getType())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAnonymousOrLocal(field.getType())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
|
|
||||||
if (!list.isEmpty()) {
|
|
||||||
FieldAttributes fieldAttributes = new FieldAttributes(field);
|
|
||||||
for (ExclusionStrategy exclusionStrategy : list) {
|
|
||||||
if (exclusionStrategy.shouldSkipField(fieldAttributes)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean excludeClass(Class<?> clazz, boolean serialize) {
|
|
||||||
if (version != Excluder.IGNORE_VERSIONS
|
|
||||||
&& !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serializeInnerClasses && isInnerClass(clazz)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAnonymousOrLocal(clazz)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
|
|
||||||
for (ExclusionStrategy exclusionStrategy : list) {
|
|
||||||
if (exclusionStrategy.shouldSkipClass(clazz)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAnonymousOrLocal(Class<?> clazz) {
|
|
||||||
return !Enum.class.isAssignableFrom(clazz)
|
|
||||||
&& (clazz.isAnonymousClass() || clazz.isLocalClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isInnerClass(Class<?> clazz) {
|
|
||||||
return clazz.isMemberClass() && !isStatic(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isStatic(Class<?> clazz) {
|
|
||||||
return (clazz.getModifiers() & Modifier.STATIC) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidVersion(Since since, Until until) {
|
|
||||||
return isValidSince(since) && isValidUntil(until);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidSince(Since annotation) {
|
|
||||||
if (annotation != null) {
|
|
||||||
double annotationVersion = annotation.value();
|
|
||||||
if (annotationVersion > version) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidUntil(Until annotation) {
|
|
||||||
if (annotation != null) {
|
|
||||||
double annotationVersion = annotation.value();
|
|
||||||
if (annotationVersion <= version) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal-only APIs of JsonReader available only to other classes in Gson.
|
|
||||||
*/
|
|
||||||
public abstract class JsonReaderInternalAccess {
|
|
||||||
public static JsonReaderInternalAccess INSTANCE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the type of the current property name token to a string value.
|
|
||||||
*/
|
|
||||||
public abstract void promoteNameToValue(JsonReader reader) throws IOException;
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import java.io.ObjectStreamException;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class holds a number value that is lazily converted to a specific number type
|
|
||||||
*
|
|
||||||
* @author Inderjeet Singh
|
|
||||||
*/
|
|
||||||
public final class LazilyParsedNumber extends Number {
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
/** @param value must not be null */
|
|
||||||
public LazilyParsedNumber(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int intValue() {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(value);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
try {
|
|
||||||
return (int) Long.parseLong(value);
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
return new BigDecimal(value).intValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long longValue() {
|
|
||||||
try {
|
|
||||||
return Long.parseLong(value);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return new BigDecimal(value).longValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float floatValue() {
|
|
||||||
return Float.parseFloat(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double doubleValue() {
|
|
||||||
return Double.parseDouble(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If somebody is unlucky enough to have to serialize one of these, serialize
|
|
||||||
* it as a BigDecimal so that they won't need Gson on the other side to
|
|
||||||
* deserialize it.
|
|
||||||
*/
|
|
||||||
private Object writeReplace() throws ObjectStreamException {
|
|
||||||
return new BigDecimal(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return value.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj instanceof LazilyParsedNumber) {
|
|
||||||
LazilyParsedNumber other = (LazilyParsedNumber) obj;
|
|
||||||
return value == other.value || value.equals(other.value);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,856 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
|
||||||
* Copyright (C) 2012 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import java.io.ObjectStreamException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of comparable keys to values. Unlike {@code TreeMap}, this class uses
|
|
||||||
* insertion order for iteration order. Comparison order is only used as an
|
|
||||||
* optimization for efficient insertion and removal.
|
|
||||||
*
|
|
||||||
* <p>This implementation was derived from Android 4.1's TreeMap and
|
|
||||||
* LinkedHashMap classes.
|
|
||||||
*/
|
|
||||||
public final class LinkedHashTreeMap<K, V> extends AbstractMap<K, V> implements Serializable {
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" }) // to avoid Comparable<Comparable<Comparable<...>>>
|
|
||||||
private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() {
|
|
||||||
public int compare(Comparable a, Comparable b) {
|
|
||||||
return a.compareTo(b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Comparator<? super K> comparator;
|
|
||||||
Node<K, V>[] table;
|
|
||||||
final Node<K, V> header;
|
|
||||||
int size = 0;
|
|
||||||
int modCount = 0;
|
|
||||||
int threshold;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a natural order, empty tree map whose keys must be mutually
|
|
||||||
* comparable and non-null.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked") // unsafe! this assumes K is comparable
|
|
||||||
public LinkedHashTreeMap() {
|
|
||||||
this((Comparator<? super K>) NATURAL_ORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a tree map ordered by {@code comparator}. This map's keys may only
|
|
||||||
* be null if {@code comparator} permits.
|
|
||||||
*
|
|
||||||
* @param comparator the comparator to order elements with, or {@code null} to
|
|
||||||
* use the natural ordering.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" }) // unsafe! if comparator is null, this assumes K is comparable
|
|
||||||
public LinkedHashTreeMap(Comparator<? super K> comparator) {
|
|
||||||
this.comparator = comparator != null
|
|
||||||
? comparator
|
|
||||||
: (Comparator) NATURAL_ORDER;
|
|
||||||
this.header = new Node<>();
|
|
||||||
this.table = new Node[16]; // TODO: sizing/resizing policies
|
|
||||||
this.threshold = (table.length / 2) + (table.length / 4); // 3/4 capacity
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V get(Object key) {
|
|
||||||
Node<K, V> node = findByObject(key);
|
|
||||||
return node != null ? node.value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean containsKey(Object key) {
|
|
||||||
return findByObject(key) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V put(K key, V value) {
|
|
||||||
if (key == null) {
|
|
||||||
throw new NullPointerException("key == null");
|
|
||||||
}
|
|
||||||
Node<K, V> created = find(key, true);
|
|
||||||
V result = created.value;
|
|
||||||
created.value = value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void clear() {
|
|
||||||
Arrays.fill(table, null);
|
|
||||||
size = 0;
|
|
||||||
modCount++;
|
|
||||||
|
|
||||||
// Clear all links to help GC
|
|
||||||
Node<K, V> header = this.header;
|
|
||||||
for (Node<K, V> e = header.next; e != header; ) {
|
|
||||||
Node<K, V> next = e.next;
|
|
||||||
e.next = e.prev = null;
|
|
||||||
e = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
header.next = header.prev = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V remove(Object key) {
|
|
||||||
Node<K, V> node = removeInternalByKey(key);
|
|
||||||
return node != null ? node.value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the node at or adjacent to the given key, creating it if requested.
|
|
||||||
*
|
|
||||||
* @throws ClassCastException if {@code key} and the tree's keys aren't
|
|
||||||
* mutually comparable.
|
|
||||||
*/
|
|
||||||
Node<K, V> find(K key, boolean create) {
|
|
||||||
Comparator<? super K> comparator = this.comparator;
|
|
||||||
Node<K, V>[] table = this.table;
|
|
||||||
int hash = secondaryHash(key.hashCode());
|
|
||||||
int index = hash & (table.length - 1);
|
|
||||||
Node<K, V> nearest = table[index];
|
|
||||||
int comparison = 0;
|
|
||||||
|
|
||||||
if (nearest != null) {
|
|
||||||
// Micro-optimization: avoid polymorphic calls to Comparator.compare().
|
|
||||||
@SuppressWarnings("unchecked") // Throws a ClassCastException below if there's trouble.
|
|
||||||
Comparable<Object> comparableKey = (comparator == NATURAL_ORDER)
|
|
||||||
? (Comparable<Object>) key
|
|
||||||
: null;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
comparison = (comparableKey != null)
|
|
||||||
? comparableKey.compareTo(nearest.key)
|
|
||||||
: comparator.compare(key, nearest.key);
|
|
||||||
|
|
||||||
// We found the requested key.
|
|
||||||
if (comparison == 0) {
|
|
||||||
return nearest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it exists, the key is in a subtree. Go deeper.
|
|
||||||
Node<K, V> child = (comparison < 0) ? nearest.left : nearest.right;
|
|
||||||
if (child == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nearest = child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The key doesn't exist in this tree.
|
|
||||||
if (!create) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the node and add it to the tree or the table.
|
|
||||||
Node<K, V> header = this.header;
|
|
||||||
Node<K, V> created;
|
|
||||||
if (nearest == null) {
|
|
||||||
// Check that the value is comparable if we didn't do any comparisons.
|
|
||||||
if (comparator == NATURAL_ORDER && !(key instanceof Comparable)) {
|
|
||||||
throw new ClassCastException(key.getClass().getName() + " is not Comparable");
|
|
||||||
}
|
|
||||||
created = new Node<>(nearest, key, hash, header, header.prev);
|
|
||||||
table[index] = created;
|
|
||||||
} else {
|
|
||||||
created = new Node<>(nearest, key, hash, header, header.prev);
|
|
||||||
if (comparison < 0) { // nearest.key is higher
|
|
||||||
nearest.left = created;
|
|
||||||
} else { // comparison > 0, nearest.key is lower
|
|
||||||
nearest.right = created;
|
|
||||||
}
|
|
||||||
rebalance(nearest, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size++ > threshold) {
|
|
||||||
doubleCapacity();
|
|
||||||
}
|
|
||||||
modCount++;
|
|
||||||
|
|
||||||
return created;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Node<K, V> findByObject(Object key) {
|
|
||||||
try {
|
|
||||||
return key != null ? find((K) key, false) : null;
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this map's entry that has the same key and value as {@code
|
|
||||||
* entry}, or null if this map has no such entry.
|
|
||||||
*
|
|
||||||
* <p>This method uses the comparator for key equality rather than {@code
|
|
||||||
* equals}. If this map's comparator isn't consistent with equals (such as
|
|
||||||
* {@code String.CASE_INSENSITIVE_ORDER}), then {@code remove()} and {@code
|
|
||||||
* contains()} will violate the collections API.
|
|
||||||
*/
|
|
||||||
Node<K, V> findByEntry(Entry<?, ?> entry) {
|
|
||||||
Node<K, V> mine = findByObject(entry.getKey());
|
|
||||||
boolean valuesEqual = mine != null && equal(mine.value, entry.getValue());
|
|
||||||
return valuesEqual ? mine : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean equal(Object a, Object b) {
|
|
||||||
return a == b || (a != null && a.equals(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies a supplemental hash function to a given hashCode, which defends
|
|
||||||
* against poor quality hash functions. This is critical because HashMap
|
|
||||||
* uses power-of-two length hash tables, that otherwise encounter collisions
|
|
||||||
* for hashCodes that do not differ in lower or upper bits.
|
|
||||||
*/
|
|
||||||
private static int secondaryHash(int h) {
|
|
||||||
// Doug Lea's supplemental hash function
|
|
||||||
h ^= (h >>> 20) ^ (h >>> 12);
|
|
||||||
return h ^ (h >>> 7) ^ (h >>> 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes {@code node} from this tree, rearranging the tree's structure as
|
|
||||||
* necessary.
|
|
||||||
*
|
|
||||||
* @param unlink true to also unlink this node from the iteration linked list.
|
|
||||||
*/
|
|
||||||
void removeInternal(Node<K, V> node, boolean unlink) {
|
|
||||||
if (unlink) {
|
|
||||||
node.prev.next = node.next;
|
|
||||||
node.next.prev = node.prev;
|
|
||||||
node.next = node.prev = null; // Help the GC (for performance)
|
|
||||||
}
|
|
||||||
|
|
||||||
Node<K, V> left = node.left;
|
|
||||||
Node<K, V> right = node.right;
|
|
||||||
Node<K, V> originalParent = node.parent;
|
|
||||||
if (left != null && right != null) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To remove a node with both left and right subtrees, move an
|
|
||||||
* adjacent node from one of those subtrees into this node's place.
|
|
||||||
*
|
|
||||||
* Removing the adjacent node may change this node's subtrees. This
|
|
||||||
* node may no longer have two subtrees once the adjacent node is
|
|
||||||
* gone!
|
|
||||||
*/
|
|
||||||
|
|
||||||
Node<K, V> adjacent = (left.height > right.height) ? left.last() : right.first();
|
|
||||||
removeInternal(adjacent, false); // takes care of rebalance and size--
|
|
||||||
|
|
||||||
int leftHeight = 0;
|
|
||||||
left = node.left;
|
|
||||||
if (left != null) {
|
|
||||||
leftHeight = left.height;
|
|
||||||
adjacent.left = left;
|
|
||||||
left.parent = adjacent;
|
|
||||||
node.left = null;
|
|
||||||
}
|
|
||||||
int rightHeight = 0;
|
|
||||||
right = node.right;
|
|
||||||
if (right != null) {
|
|
||||||
rightHeight = right.height;
|
|
||||||
adjacent.right = right;
|
|
||||||
right.parent = adjacent;
|
|
||||||
node.right = null;
|
|
||||||
}
|
|
||||||
adjacent.height = Math.max(leftHeight, rightHeight) + 1;
|
|
||||||
replaceInParent(node, adjacent);
|
|
||||||
return;
|
|
||||||
} else if (left != null) {
|
|
||||||
replaceInParent(node, left);
|
|
||||||
node.left = null;
|
|
||||||
} else if (right != null) {
|
|
||||||
replaceInParent(node, right);
|
|
||||||
node.right = null;
|
|
||||||
} else {
|
|
||||||
replaceInParent(node, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
rebalance(originalParent, false);
|
|
||||||
size--;
|
|
||||||
modCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node<K, V> removeInternalByKey(Object key) {
|
|
||||||
Node<K, V> node = findByObject(key);
|
|
||||||
if (node != null) {
|
|
||||||
removeInternal(node, true);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void replaceInParent(Node<K, V> node, Node<K, V> replacement) {
|
|
||||||
Node<K, V> parent = node.parent;
|
|
||||||
node.parent = null;
|
|
||||||
if (replacement != null) {
|
|
||||||
replacement.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent != null) {
|
|
||||||
if (parent.left == node) {
|
|
||||||
parent.left = replacement;
|
|
||||||
} else {
|
|
||||||
assert (parent.right == node);
|
|
||||||
parent.right = replacement;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int index = node.hash & (table.length - 1);
|
|
||||||
table[index] = replacement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rebalances the tree by making any AVL rotations necessary between the
|
|
||||||
* newly-unbalanced node and the tree's root.
|
|
||||||
*
|
|
||||||
* @param insert true if the node was unbalanced by an insert; false if it
|
|
||||||
* was by a removal.
|
|
||||||
*/
|
|
||||||
private void rebalance(Node<K, V> unbalanced, boolean insert) {
|
|
||||||
for (Node<K, V> node = unbalanced; node != null; node = node.parent) {
|
|
||||||
Node<K, V> left = node.left;
|
|
||||||
Node<K, V> right = node.right;
|
|
||||||
int leftHeight = left != null ? left.height : 0;
|
|
||||||
int rightHeight = right != null ? right.height : 0;
|
|
||||||
|
|
||||||
int delta = leftHeight - rightHeight;
|
|
||||||
if (delta == -2) {
|
|
||||||
Node<K, V> rightLeft = right.left;
|
|
||||||
Node<K, V> rightRight = right.right;
|
|
||||||
int rightRightHeight = rightRight != null ? rightRight.height : 0;
|
|
||||||
int rightLeftHeight = rightLeft != null ? rightLeft.height : 0;
|
|
||||||
|
|
||||||
int rightDelta = rightLeftHeight - rightRightHeight;
|
|
||||||
if (rightDelta == -1 || (rightDelta == 0 && !insert)) {
|
|
||||||
rotateLeft(node); // AVL right right
|
|
||||||
} else {
|
|
||||||
assert (rightDelta == 1);
|
|
||||||
rotateRight(right); // AVL right left
|
|
||||||
rotateLeft(node);
|
|
||||||
}
|
|
||||||
if (insert) {
|
|
||||||
break; // no further rotations will be necessary
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (delta == 2) {
|
|
||||||
Node<K, V> leftLeft = left.left;
|
|
||||||
Node<K, V> leftRight = left.right;
|
|
||||||
int leftRightHeight = leftRight != null ? leftRight.height : 0;
|
|
||||||
int leftLeftHeight = leftLeft != null ? leftLeft.height : 0;
|
|
||||||
|
|
||||||
int leftDelta = leftLeftHeight - leftRightHeight;
|
|
||||||
if (leftDelta == 1 || (leftDelta == 0 && !insert)) {
|
|
||||||
rotateRight(node); // AVL left left
|
|
||||||
} else {
|
|
||||||
assert (leftDelta == -1);
|
|
||||||
rotateLeft(left); // AVL left right
|
|
||||||
rotateRight(node);
|
|
||||||
}
|
|
||||||
if (insert) {
|
|
||||||
break; // no further rotations will be necessary
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (delta == 0) {
|
|
||||||
node.height = leftHeight + 1; // leftHeight == rightHeight
|
|
||||||
if (insert) {
|
|
||||||
break; // the insert caused balance, so rebalancing is done!
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
assert (delta == -1 || delta == 1);
|
|
||||||
node.height = Math.max(leftHeight, rightHeight) + 1;
|
|
||||||
if (!insert) {
|
|
||||||
break; // the height hasn't changed, so rebalancing is done!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotates the subtree so that its root's right child is the new root.
|
|
||||||
*/
|
|
||||||
private void rotateLeft(Node<K, V> root) {
|
|
||||||
Node<K, V> left = root.left;
|
|
||||||
Node<K, V> pivot = root.right;
|
|
||||||
Node<K, V> pivotLeft = pivot.left;
|
|
||||||
Node<K, V> pivotRight = pivot.right;
|
|
||||||
|
|
||||||
// move the pivot's left child to the root's right
|
|
||||||
root.right = pivotLeft;
|
|
||||||
if (pivotLeft != null) {
|
|
||||||
pivotLeft.parent = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceInParent(root, pivot);
|
|
||||||
|
|
||||||
// move the root to the pivot's left
|
|
||||||
pivot.left = root;
|
|
||||||
root.parent = pivot;
|
|
||||||
|
|
||||||
// fix heights
|
|
||||||
root.height = Math.max(left != null ? left.height : 0,
|
|
||||||
pivotLeft != null ? pivotLeft.height : 0) + 1;
|
|
||||||
pivot.height = Math.max(root.height,
|
|
||||||
pivotRight != null ? pivotRight.height : 0) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotates the subtree so that its root's left child is the new root.
|
|
||||||
*/
|
|
||||||
private void rotateRight(Node<K, V> root) {
|
|
||||||
Node<K, V> pivot = root.left;
|
|
||||||
Node<K, V> right = root.right;
|
|
||||||
Node<K, V> pivotLeft = pivot.left;
|
|
||||||
Node<K, V> pivotRight = pivot.right;
|
|
||||||
|
|
||||||
// move the pivot's right child to the root's left
|
|
||||||
root.left = pivotRight;
|
|
||||||
if (pivotRight != null) {
|
|
||||||
pivotRight.parent = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceInParent(root, pivot);
|
|
||||||
|
|
||||||
// move the root to the pivot's right
|
|
||||||
pivot.right = root;
|
|
||||||
root.parent = pivot;
|
|
||||||
|
|
||||||
// fixup heights
|
|
||||||
root.height = Math.max(right != null ? right.height : 0,
|
|
||||||
pivotRight != null ? pivotRight.height : 0) + 1;
|
|
||||||
pivot.height = Math.max(root.height,
|
|
||||||
pivotLeft != null ? pivotLeft.height : 0) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private EntrySet entrySet;
|
|
||||||
private KeySet keySet;
|
|
||||||
|
|
||||||
@Override public Set<Entry<K, V>> entrySet() {
|
|
||||||
EntrySet result = entrySet;
|
|
||||||
return result != null ? result : (entrySet = new EntrySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Set<K> keySet() {
|
|
||||||
KeySet result = keySet;
|
|
||||||
return result != null ? result : (keySet = new KeySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class Node<K, V> implements Entry<K, V> {
|
|
||||||
Node<K, V> parent;
|
|
||||||
Node<K, V> left;
|
|
||||||
Node<K, V> right;
|
|
||||||
Node<K, V> next;
|
|
||||||
Node<K, V> prev;
|
|
||||||
final K key;
|
|
||||||
final int hash;
|
|
||||||
V value;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
/** Create the header entry */
|
|
||||||
Node() {
|
|
||||||
key = null;
|
|
||||||
hash = -1;
|
|
||||||
next = prev = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a regular entry */
|
|
||||||
Node(Node<K, V> parent, K key, int hash, Node<K, V> next, Node<K, V> prev) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.key = key;
|
|
||||||
this.hash = hash;
|
|
||||||
this.height = 1;
|
|
||||||
this.next = next;
|
|
||||||
this.prev = prev;
|
|
||||||
prev.next = this;
|
|
||||||
next.prev = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public K getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public V getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public V setValue(V value) {
|
|
||||||
V oldValue = this.value;
|
|
||||||
this.value = value;
|
|
||||||
return oldValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
@Override public boolean equals(Object o) {
|
|
||||||
if (o instanceof Entry) {
|
|
||||||
Entry other = (Entry) o;
|
|
||||||
return (key == null ? other.getKey() == null : key.equals(other.getKey()))
|
|
||||||
&& (value == null ? other.getValue() == null : value.equals(other.getValue()));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode() {
|
|
||||||
return (key == null ? 0 : key.hashCode())
|
|
||||||
^ (value == null ? 0 : value.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return key + "=" + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first node in this subtree.
|
|
||||||
*/
|
|
||||||
public Node<K, V> first() {
|
|
||||||
Node<K, V> node = this;
|
|
||||||
Node<K, V> child = node.left;
|
|
||||||
while (child != null) {
|
|
||||||
node = child;
|
|
||||||
child = node.left;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the last node in this subtree.
|
|
||||||
*/
|
|
||||||
public Node<K, V> last() {
|
|
||||||
Node<K, V> node = this;
|
|
||||||
Node<K, V> child = node.right;
|
|
||||||
while (child != null) {
|
|
||||||
node = child;
|
|
||||||
child = node.right;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doubleCapacity() {
|
|
||||||
table = doubleCapacity(table);
|
|
||||||
threshold = (table.length / 2) + (table.length / 4); // 3/4 capacity
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new array containing the same nodes as {@code oldTable}, but with
|
|
||||||
* twice as many trees, each of (approximately) half the previous size.
|
|
||||||
*/
|
|
||||||
static <K, V> Node<K, V>[] doubleCapacity(Node<K, V>[] oldTable) {
|
|
||||||
// TODO: don't do anything if we're already at MAX_CAPACITY
|
|
||||||
int oldCapacity = oldTable.length;
|
|
||||||
@SuppressWarnings("unchecked") // Arrays and generics don't get along.
|
|
||||||
Node<K, V>[] newTable = new Node[oldCapacity * 2];
|
|
||||||
AvlIterator<K, V> iterator = new AvlIterator<>();
|
|
||||||
AvlBuilder<K, V> leftBuilder = new AvlBuilder<>();
|
|
||||||
AvlBuilder<K, V> rightBuilder = new AvlBuilder<>();
|
|
||||||
|
|
||||||
// Split each tree into two trees.
|
|
||||||
for (int i = 0; i < oldCapacity; i++) {
|
|
||||||
Node<K, V> root = oldTable[i];
|
|
||||||
if (root == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the sizes of the left and right trees.
|
|
||||||
iterator.reset(root);
|
|
||||||
int leftSize = 0;
|
|
||||||
int rightSize = 0;
|
|
||||||
for (Node<K, V> node; (node = iterator.next()) != null; ) {
|
|
||||||
if ((node.hash & oldCapacity) == 0) {
|
|
||||||
leftSize++;
|
|
||||||
} else {
|
|
||||||
rightSize++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split the tree into two.
|
|
||||||
leftBuilder.reset(leftSize);
|
|
||||||
rightBuilder.reset(rightSize);
|
|
||||||
iterator.reset(root);
|
|
||||||
for (Node<K, V> node; (node = iterator.next()) != null; ) {
|
|
||||||
if ((node.hash & oldCapacity) == 0) {
|
|
||||||
leftBuilder.add(node);
|
|
||||||
} else {
|
|
||||||
rightBuilder.add(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate the enlarged array with these new roots.
|
|
||||||
newTable[i] = leftSize > 0 ? leftBuilder.root() : null;
|
|
||||||
newTable[i + oldCapacity] = rightSize > 0 ? rightBuilder.root() : null;
|
|
||||||
}
|
|
||||||
return newTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Walks an AVL tree in iteration order. Once a node has been returned, its
|
|
||||||
* left, right and parent links are <strong>no longer used</strong>. For this
|
|
||||||
* reason it is safe to transform these links as you walk a tree.
|
|
||||||
*
|
|
||||||
* <p><strong>Warning:</strong> this iterator is destructive. It clears the
|
|
||||||
* parent node of all nodes in the tree. It is an error to make a partial
|
|
||||||
* iteration of a tree.
|
|
||||||
*/
|
|
||||||
static class AvlIterator<K, V> {
|
|
||||||
/** This stack is a singly linked list, linked by the 'parent' field. */
|
|
||||||
private Node<K, V> stackTop;
|
|
||||||
|
|
||||||
void reset(Node<K, V> root) {
|
|
||||||
Node<K, V> stackTop = null;
|
|
||||||
for (Node<K, V> n = root; n != null; n = n.left) {
|
|
||||||
n.parent = stackTop;
|
|
||||||
stackTop = n; // Stack push.
|
|
||||||
}
|
|
||||||
this.stackTop = stackTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node<K, V> next() {
|
|
||||||
Node<K, V> stackTop = this.stackTop;
|
|
||||||
if (stackTop == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Node<K, V> result = stackTop;
|
|
||||||
stackTop = result.parent;
|
|
||||||
result.parent = null;
|
|
||||||
for (Node<K, V> n = result.right; n != null; n = n.left) {
|
|
||||||
n.parent = stackTop;
|
|
||||||
stackTop = n; // Stack push.
|
|
||||||
}
|
|
||||||
this.stackTop = stackTop;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds AVL trees of a predetermined size by accepting nodes of increasing
|
|
||||||
* value. To use:
|
|
||||||
* <ol>
|
|
||||||
* <li>Call {@link #reset} to initialize the target size <i>size</i>.
|
|
||||||
* <li>Call {@link #add} <i>size</i> times with increasing values.
|
|
||||||
* <li>Call {@link #root} to get the root of the balanced tree.
|
|
||||||
* </ol>
|
|
||||||
*
|
|
||||||
* <p>The returned tree will satisfy the AVL constraint: for every node
|
|
||||||
* <i>N</i>, the height of <i>N.left</i> and <i>N.right</i> is different by at
|
|
||||||
* most 1. It accomplishes this by omitting deepest-level leaf nodes when
|
|
||||||
* building trees whose size isn't a power of 2 minus 1.
|
|
||||||
*
|
|
||||||
* <p>Unlike rebuilding a tree from scratch, this approach requires no value
|
|
||||||
* comparisons. Using this class to create a tree of size <i>S</i> is
|
|
||||||
* {@code O(S)}.
|
|
||||||
*/
|
|
||||||
final static class AvlBuilder<K, V> {
|
|
||||||
/** This stack is a singly linked list, linked by the 'parent' field. */
|
|
||||||
private Node<K, V> stack;
|
|
||||||
private int leavesToSkip;
|
|
||||||
private int leavesSkipped;
|
|
||||||
private int size;
|
|
||||||
|
|
||||||
void reset(int targetSize) {
|
|
||||||
// compute the target tree size. This is a power of 2 minus one, like 15 or 31.
|
|
||||||
int treeCapacity = Integer.highestOneBit(targetSize) * 2 - 1;
|
|
||||||
leavesToSkip = treeCapacity - targetSize;
|
|
||||||
size = 0;
|
|
||||||
leavesSkipped = 0;
|
|
||||||
stack = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(Node<K, V> node) {
|
|
||||||
node.left = node.parent = node.right = null;
|
|
||||||
node.height = 1;
|
|
||||||
|
|
||||||
// Skip a leaf if necessary.
|
|
||||||
if (leavesToSkip > 0 && (size & 1) == 0) {
|
|
||||||
size++;
|
|
||||||
leavesToSkip--;
|
|
||||||
leavesSkipped++;
|
|
||||||
}
|
|
||||||
|
|
||||||
node.parent = stack;
|
|
||||||
stack = node; // Stack push.
|
|
||||||
size++;
|
|
||||||
|
|
||||||
// Skip a leaf if necessary.
|
|
||||||
if (leavesToSkip > 0 && (size & 1) == 0) {
|
|
||||||
size++;
|
|
||||||
leavesToSkip--;
|
|
||||||
leavesSkipped++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Combine 3 nodes into subtrees whenever the size is one less than a
|
|
||||||
* multiple of 4. For example we combine the nodes A, B, C into a
|
|
||||||
* 3-element tree with B as the root.
|
|
||||||
*
|
|
||||||
* Combine two subtrees and a spare single value whenever the size is one
|
|
||||||
* less than a multiple of 8. For example at 8 we may combine subtrees
|
|
||||||
* (A B C) and (E F G) with D as the root to form ((A B C) D (E F G)).
|
|
||||||
*
|
|
||||||
* Just as we combine single nodes when size nears a multiple of 4, and
|
|
||||||
* 3-element trees when size nears a multiple of 8, we combine subtrees of
|
|
||||||
* size (N-1) whenever the total size is 2N-1 whenever N is a power of 2.
|
|
||||||
*/
|
|
||||||
for (int scale = 4; (size & scale - 1) == scale - 1; scale *= 2) {
|
|
||||||
if (leavesSkipped == 0) {
|
|
||||||
// Pop right, center and left, then make center the top of the stack.
|
|
||||||
Node<K, V> right = stack;
|
|
||||||
Node<K, V> center = right.parent;
|
|
||||||
Node<K, V> left = center.parent;
|
|
||||||
center.parent = left.parent;
|
|
||||||
stack = center;
|
|
||||||
// Construct a tree.
|
|
||||||
center.left = left;
|
|
||||||
center.right = right;
|
|
||||||
center.height = right.height + 1;
|
|
||||||
left.parent = center;
|
|
||||||
right.parent = center;
|
|
||||||
} else if (leavesSkipped == 1) {
|
|
||||||
// Pop right and center, then make center the top of the stack.
|
|
||||||
Node<K, V> right = stack;
|
|
||||||
Node<K, V> center = right.parent;
|
|
||||||
stack = center;
|
|
||||||
// Construct a tree with no left child.
|
|
||||||
center.right = right;
|
|
||||||
center.height = right.height + 1;
|
|
||||||
right.parent = center;
|
|
||||||
leavesSkipped = 0;
|
|
||||||
} else if (leavesSkipped == 2) {
|
|
||||||
leavesSkipped = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Node<K, V> root() {
|
|
||||||
Node<K, V> stackTop = this.stack;
|
|
||||||
if (stackTop.parent != null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
return stackTop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private abstract class LinkedTreeMapIterator<T> implements Iterator<T> {
|
|
||||||
Node<K, V> next = header.next;
|
|
||||||
Node<K, V> lastReturned = null;
|
|
||||||
int expectedModCount = modCount;
|
|
||||||
|
|
||||||
LinkedTreeMapIterator() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean hasNext() {
|
|
||||||
return next != header;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Node<K, V> nextNode() {
|
|
||||||
Node<K, V> e = next;
|
|
||||||
if (e == header) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
if (modCount != expectedModCount) {
|
|
||||||
throw new ConcurrentModificationException();
|
|
||||||
}
|
|
||||||
next = e.next;
|
|
||||||
return lastReturned = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void remove() {
|
|
||||||
if (lastReturned == null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
removeInternal(lastReturned, true);
|
|
||||||
lastReturned = null;
|
|
||||||
expectedModCount = modCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class EntrySet extends AbstractSet<Entry<K, V>> {
|
|
||||||
@Override public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Iterator<Entry<K, V>> iterator() {
|
|
||||||
return new LinkedTreeMapIterator<Entry<K, V>>() {
|
|
||||||
public Entry<K, V> next() {
|
|
||||||
return nextNode();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean contains(Object o) {
|
|
||||||
return o instanceof Entry && findByEntry((Entry<?, ?>) o) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean remove(Object o) {
|
|
||||||
if (!(o instanceof Entry)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node<K, V> node = findByEntry((Entry<?, ?>) o);
|
|
||||||
if (node == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
removeInternal(node, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void clear() {
|
|
||||||
LinkedHashTreeMap.this.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class KeySet extends AbstractSet<K> {
|
|
||||||
@Override public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Iterator<K> iterator() {
|
|
||||||
return new LinkedTreeMapIterator<K>() {
|
|
||||||
public K next() {
|
|
||||||
return nextNode().key;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean contains(Object o) {
|
|
||||||
return containsKey(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean remove(Object key) {
|
|
||||||
return removeInternalByKey(key) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void clear() {
|
|
||||||
LinkedHashTreeMap.this.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If somebody is unlucky enough to have to serialize one of these, serialize
|
|
||||||
* it as a LinkedHashMap so that they won't need Gson on the other side to
|
|
||||||
* deserialize it. Using serialization defeats our DoS defence, so most apps
|
|
||||||
* shouldn't use it.
|
|
||||||
*/
|
|
||||||
private Object writeReplace() throws ObjectStreamException {
|
|
||||||
return new LinkedHashMap<>(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,623 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 The Android Open Source Project
|
|
||||||
* Copyright (C) 2012 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import java.io.ObjectStreamException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of comparable keys to values. Unlike {@code TreeMap}, this class uses
|
|
||||||
* insertion order for iteration order. Comparison order is only used as an
|
|
||||||
* optimization for efficient insertion and removal.
|
|
||||||
*
|
|
||||||
* <p>This implementation was derived from Android 4.1's TreeMap class.
|
|
||||||
*/
|
|
||||||
public final class LinkedTreeMap<K, V> extends AbstractMap<K, V> implements Serializable {
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" }) // to avoid Comparable<Comparable<Comparable<...>>>
|
|
||||||
private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() {
|
|
||||||
public int compare(Comparable a, Comparable b) {
|
|
||||||
return a.compareTo(b);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Comparator<? super K> comparator;
|
|
||||||
Node<K, V> root;
|
|
||||||
int size = 0;
|
|
||||||
int modCount = 0;
|
|
||||||
|
|
||||||
// Used to preserve iteration order
|
|
||||||
final Node<K, V> header = new Node<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a natural order, empty tree map whose keys must be mutually
|
|
||||||
* comparable and non-null.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked") // unsafe! this assumes K is comparable
|
|
||||||
public LinkedTreeMap() {
|
|
||||||
this((Comparator<? super K>) NATURAL_ORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a tree map ordered by {@code comparator}. This map's keys may only
|
|
||||||
* be null if {@code comparator} permits.
|
|
||||||
*
|
|
||||||
* @param comparator the comparator to order elements with, or {@code null} to
|
|
||||||
* use the natural ordering.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" }) // unsafe! if comparator is null, this assumes K is comparable
|
|
||||||
public LinkedTreeMap(Comparator<? super K> comparator) {
|
|
||||||
this.comparator = comparator != null
|
|
||||||
? comparator
|
|
||||||
: (Comparator) NATURAL_ORDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V get(Object key) {
|
|
||||||
Node<K, V> node = findByObject(key);
|
|
||||||
return node != null ? node.value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean containsKey(Object key) {
|
|
||||||
return findByObject(key) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V put(K key, V value) {
|
|
||||||
if (key == null) {
|
|
||||||
throw new NullPointerException("key == null");
|
|
||||||
}
|
|
||||||
Node<K, V> created = find(key, true);
|
|
||||||
V result = created.value;
|
|
||||||
created.value = value;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void clear() {
|
|
||||||
root = null;
|
|
||||||
size = 0;
|
|
||||||
modCount++;
|
|
||||||
|
|
||||||
// Clear iteration order
|
|
||||||
Node<K, V> header = this.header;
|
|
||||||
header.next = header.prev = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public V remove(Object key) {
|
|
||||||
Node<K, V> node = removeInternalByKey(key);
|
|
||||||
return node != null ? node.value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the node at or adjacent to the given key, creating it if requested.
|
|
||||||
*
|
|
||||||
* @throws ClassCastException if {@code key} and the tree's keys aren't
|
|
||||||
* mutually comparable.
|
|
||||||
*/
|
|
||||||
Node<K, V> find(K key, boolean create) {
|
|
||||||
Comparator<? super K> comparator = this.comparator;
|
|
||||||
Node<K, V> nearest = root;
|
|
||||||
int comparison = 0;
|
|
||||||
|
|
||||||
if (nearest != null) {
|
|
||||||
// Micro-optimization: avoid polymorphic calls to Comparator.compare().
|
|
||||||
@SuppressWarnings("unchecked") // Throws a ClassCastException below if there's trouble.
|
|
||||||
Comparable<Object> comparableKey = (comparator == NATURAL_ORDER)
|
|
||||||
? (Comparable<Object>) key
|
|
||||||
: null;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
comparison = (comparableKey != null)
|
|
||||||
? comparableKey.compareTo(nearest.key)
|
|
||||||
: comparator.compare(key, nearest.key);
|
|
||||||
|
|
||||||
// We found the requested key.
|
|
||||||
if (comparison == 0) {
|
|
||||||
return nearest;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it exists, the key is in a subtree. Go deeper.
|
|
||||||
Node<K, V> child = (comparison < 0) ? nearest.left : nearest.right;
|
|
||||||
if (child == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
nearest = child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The key doesn't exist in this tree.
|
|
||||||
if (!create) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the node and add it to the tree or the table.
|
|
||||||
Node<K, V> header = this.header;
|
|
||||||
Node<K, V> created;
|
|
||||||
if (nearest == null) {
|
|
||||||
// Check that the value is comparable if we didn't do any comparisons.
|
|
||||||
if (comparator == NATURAL_ORDER && !(key instanceof Comparable)) {
|
|
||||||
throw new ClassCastException(key.getClass().getName() + " is not Comparable");
|
|
||||||
}
|
|
||||||
created = new Node<>(nearest, key, header, header.prev);
|
|
||||||
root = created;
|
|
||||||
} else {
|
|
||||||
created = new Node<>(nearest, key, header, header.prev);
|
|
||||||
if (comparison < 0) { // nearest.key is higher
|
|
||||||
nearest.left = created;
|
|
||||||
} else { // comparison > 0, nearest.key is lower
|
|
||||||
nearest.right = created;
|
|
||||||
}
|
|
||||||
rebalance(nearest, true);
|
|
||||||
}
|
|
||||||
size++;
|
|
||||||
modCount++;
|
|
||||||
|
|
||||||
return created;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Node<K, V> findByObject(Object key) {
|
|
||||||
try {
|
|
||||||
return key != null ? find((K) key, false) : null;
|
|
||||||
} catch (ClassCastException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this map's entry that has the same key and value as {@code
|
|
||||||
* entry}, or null if this map has no such entry.
|
|
||||||
*
|
|
||||||
* <p>This method uses the comparator for key equality rather than {@code
|
|
||||||
* equals}. If this map's comparator isn't consistent with equals (such as
|
|
||||||
* {@code String.CASE_INSENSITIVE_ORDER}), then {@code remove()} and {@code
|
|
||||||
* contains()} will violate the collections API.
|
|
||||||
*/
|
|
||||||
Node<K, V> findByEntry(Entry<?, ?> entry) {
|
|
||||||
Node<K, V> mine = findByObject(entry.getKey());
|
|
||||||
boolean valuesEqual = mine != null && equal(mine.value, entry.getValue());
|
|
||||||
return valuesEqual ? mine : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean equal(Object a, Object b) {
|
|
||||||
return a == b || (a != null && a.equals(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes {@code node} from this tree, rearranging the tree's structure as
|
|
||||||
* necessary.
|
|
||||||
*
|
|
||||||
* @param unlink true to also unlink this node from the iteration linked list.
|
|
||||||
*/
|
|
||||||
void removeInternal(Node<K, V> node, boolean unlink) {
|
|
||||||
if (unlink) {
|
|
||||||
node.prev.next = node.next;
|
|
||||||
node.next.prev = node.prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node<K, V> left = node.left;
|
|
||||||
Node<K, V> right = node.right;
|
|
||||||
Node<K, V> originalParent = node.parent;
|
|
||||||
if (left != null && right != null) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To remove a node with both left and right subtrees, move an
|
|
||||||
* adjacent node from one of those subtrees into this node's place.
|
|
||||||
*
|
|
||||||
* Removing the adjacent node may change this node's subtrees. This
|
|
||||||
* node may no longer have two subtrees once the adjacent node is
|
|
||||||
* gone!
|
|
||||||
*/
|
|
||||||
|
|
||||||
Node<K, V> adjacent = (left.height > right.height) ? left.last() : right.first();
|
|
||||||
removeInternal(adjacent, false); // takes care of rebalance and size--
|
|
||||||
|
|
||||||
int leftHeight = 0;
|
|
||||||
left = node.left;
|
|
||||||
if (left != null) {
|
|
||||||
leftHeight = left.height;
|
|
||||||
adjacent.left = left;
|
|
||||||
left.parent = adjacent;
|
|
||||||
node.left = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rightHeight = 0;
|
|
||||||
right = node.right;
|
|
||||||
if (right != null) {
|
|
||||||
rightHeight = right.height;
|
|
||||||
adjacent.right = right;
|
|
||||||
right.parent = adjacent;
|
|
||||||
node.right = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
adjacent.height = Math.max(leftHeight, rightHeight) + 1;
|
|
||||||
replaceInParent(node, adjacent);
|
|
||||||
return;
|
|
||||||
} else if (left != null) {
|
|
||||||
replaceInParent(node, left);
|
|
||||||
node.left = null;
|
|
||||||
} else if (right != null) {
|
|
||||||
replaceInParent(node, right);
|
|
||||||
node.right = null;
|
|
||||||
} else {
|
|
||||||
replaceInParent(node, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
rebalance(originalParent, false);
|
|
||||||
size--;
|
|
||||||
modCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node<K, V> removeInternalByKey(Object key) {
|
|
||||||
Node<K, V> node = findByObject(key);
|
|
||||||
if (node != null) {
|
|
||||||
removeInternal(node, true);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void replaceInParent(Node<K, V> node, Node<K, V> replacement) {
|
|
||||||
Node<K, V> parent = node.parent;
|
|
||||||
node.parent = null;
|
|
||||||
if (replacement != null) {
|
|
||||||
replacement.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent != null) {
|
|
||||||
if (parent.left == node) {
|
|
||||||
parent.left = replacement;
|
|
||||||
} else {
|
|
||||||
assert (parent.right == node);
|
|
||||||
parent.right = replacement;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
root = replacement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rebalances the tree by making any AVL rotations necessary between the
|
|
||||||
* newly-unbalanced node and the tree's root.
|
|
||||||
*
|
|
||||||
* @param insert true if the node was unbalanced by an insert; false if it
|
|
||||||
* was by a removal.
|
|
||||||
*/
|
|
||||||
private void rebalance(Node<K, V> unbalanced, boolean insert) {
|
|
||||||
for (Node<K, V> node = unbalanced; node != null; node = node.parent) {
|
|
||||||
Node<K, V> left = node.left;
|
|
||||||
Node<K, V> right = node.right;
|
|
||||||
int leftHeight = left != null ? left.height : 0;
|
|
||||||
int rightHeight = right != null ? right.height : 0;
|
|
||||||
|
|
||||||
int delta = leftHeight - rightHeight;
|
|
||||||
if (delta == -2) {
|
|
||||||
Node<K, V> rightLeft = right.left;
|
|
||||||
Node<K, V> rightRight = right.right;
|
|
||||||
int rightRightHeight = rightRight != null ? rightRight.height : 0;
|
|
||||||
int rightLeftHeight = rightLeft != null ? rightLeft.height : 0;
|
|
||||||
|
|
||||||
int rightDelta = rightLeftHeight - rightRightHeight;
|
|
||||||
if (rightDelta == -1 || (rightDelta == 0 && !insert)) {
|
|
||||||
rotateLeft(node); // AVL right right
|
|
||||||
} else {
|
|
||||||
assert (rightDelta == 1);
|
|
||||||
rotateRight(right); // AVL right left
|
|
||||||
rotateLeft(node);
|
|
||||||
}
|
|
||||||
if (insert) {
|
|
||||||
break; // no further rotations will be necessary
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (delta == 2) {
|
|
||||||
Node<K, V> leftLeft = left.left;
|
|
||||||
Node<K, V> leftRight = left.right;
|
|
||||||
int leftRightHeight = leftRight != null ? leftRight.height : 0;
|
|
||||||
int leftLeftHeight = leftLeft != null ? leftLeft.height : 0;
|
|
||||||
|
|
||||||
int leftDelta = leftLeftHeight - leftRightHeight;
|
|
||||||
if (leftDelta == 1 || (leftDelta == 0 && !insert)) {
|
|
||||||
rotateRight(node); // AVL left left
|
|
||||||
} else {
|
|
||||||
assert (leftDelta == -1);
|
|
||||||
rotateLeft(left); // AVL left right
|
|
||||||
rotateRight(node);
|
|
||||||
}
|
|
||||||
if (insert) {
|
|
||||||
break; // no further rotations will be necessary
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (delta == 0) {
|
|
||||||
node.height = leftHeight + 1; // leftHeight == rightHeight
|
|
||||||
if (insert) {
|
|
||||||
break; // the insert caused balance, so rebalancing is done!
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
assert (delta == -1 || delta == 1);
|
|
||||||
node.height = Math.max(leftHeight, rightHeight) + 1;
|
|
||||||
if (!insert) {
|
|
||||||
break; // the height hasn't changed, so rebalancing is done!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotates the subtree so that its root's right child is the new root.
|
|
||||||
*/
|
|
||||||
private void rotateLeft(Node<K, V> root) {
|
|
||||||
Node<K, V> left = root.left;
|
|
||||||
Node<K, V> pivot = root.right;
|
|
||||||
Node<K, V> pivotLeft = pivot.left;
|
|
||||||
Node<K, V> pivotRight = pivot.right;
|
|
||||||
|
|
||||||
// move the pivot's left child to the root's right
|
|
||||||
root.right = pivotLeft;
|
|
||||||
if (pivotLeft != null) {
|
|
||||||
pivotLeft.parent = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceInParent(root, pivot);
|
|
||||||
|
|
||||||
// move the root to the pivot's left
|
|
||||||
pivot.left = root;
|
|
||||||
root.parent = pivot;
|
|
||||||
|
|
||||||
// fix heights
|
|
||||||
root.height = Math.max(left != null ? left.height : 0,
|
|
||||||
pivotLeft != null ? pivotLeft.height : 0) + 1;
|
|
||||||
pivot.height = Math.max(root.height,
|
|
||||||
pivotRight != null ? pivotRight.height : 0) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotates the subtree so that its root's left child is the new root.
|
|
||||||
*/
|
|
||||||
private void rotateRight(Node<K, V> root) {
|
|
||||||
Node<K, V> pivot = root.left;
|
|
||||||
Node<K, V> right = root.right;
|
|
||||||
Node<K, V> pivotLeft = pivot.left;
|
|
||||||
Node<K, V> pivotRight = pivot.right;
|
|
||||||
|
|
||||||
// move the pivot's right child to the root's left
|
|
||||||
root.left = pivotRight;
|
|
||||||
if (pivotRight != null) {
|
|
||||||
pivotRight.parent = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
replaceInParent(root, pivot);
|
|
||||||
|
|
||||||
// move the root to the pivot's right
|
|
||||||
pivot.right = root;
|
|
||||||
root.parent = pivot;
|
|
||||||
|
|
||||||
// fixup heights
|
|
||||||
root.height = Math.max(right != null ? right.height : 0,
|
|
||||||
pivotRight != null ? pivotRight.height : 0) + 1;
|
|
||||||
pivot.height = Math.max(root.height,
|
|
||||||
pivotLeft != null ? pivotLeft.height : 0) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private EntrySet entrySet;
|
|
||||||
private KeySet keySet;
|
|
||||||
|
|
||||||
@Override public Set<Entry<K, V>> entrySet() {
|
|
||||||
EntrySet result = entrySet;
|
|
||||||
return result != null ? result : (entrySet = new EntrySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Set<K> keySet() {
|
|
||||||
KeySet result = keySet;
|
|
||||||
return result != null ? result : (keySet = new KeySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
static final class Node<K, V> implements Entry<K, V> {
|
|
||||||
Node<K, V> parent;
|
|
||||||
Node<K, V> left;
|
|
||||||
Node<K, V> right;
|
|
||||||
Node<K, V> next;
|
|
||||||
Node<K, V> prev;
|
|
||||||
final K key;
|
|
||||||
V value;
|
|
||||||
int height;
|
|
||||||
|
|
||||||
/** Create the header entry */
|
|
||||||
Node() {
|
|
||||||
key = null;
|
|
||||||
next = prev = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a regular entry */
|
|
||||||
Node(Node<K, V> parent, K key, Node<K, V> next, Node<K, V> prev) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.key = key;
|
|
||||||
this.height = 1;
|
|
||||||
this.next = next;
|
|
||||||
this.prev = prev;
|
|
||||||
prev.next = this;
|
|
||||||
next.prev = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public K getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public V getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public V setValue(V value) {
|
|
||||||
V oldValue = this.value;
|
|
||||||
this.value = value;
|
|
||||||
return oldValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
@Override public boolean equals(Object o) {
|
|
||||||
if (o instanceof Entry) {
|
|
||||||
Entry other = (Entry) o;
|
|
||||||
return (key == null ? other.getKey() == null : key.equals(other.getKey()))
|
|
||||||
&& (value == null ? other.getValue() == null : value.equals(other.getValue()));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode() {
|
|
||||||
return (key == null ? 0 : key.hashCode())
|
|
||||||
^ (value == null ? 0 : value.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String toString() {
|
|
||||||
return key + "=" + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first node in this subtree.
|
|
||||||
*/
|
|
||||||
public Node<K, V> first() {
|
|
||||||
Node<K, V> node = this;
|
|
||||||
Node<K, V> child = node.left;
|
|
||||||
while (child != null) {
|
|
||||||
node = child;
|
|
||||||
child = node.left;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the last node in this subtree.
|
|
||||||
*/
|
|
||||||
public Node<K, V> last() {
|
|
||||||
Node<K, V> node = this;
|
|
||||||
Node<K, V> child = node.right;
|
|
||||||
while (child != null) {
|
|
||||||
node = child;
|
|
||||||
child = node.right;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private abstract class LinkedTreeMapIterator<T> implements Iterator<T> {
|
|
||||||
Node<K, V> next = header.next;
|
|
||||||
Node<K, V> lastReturned = null;
|
|
||||||
int expectedModCount = modCount;
|
|
||||||
|
|
||||||
LinkedTreeMapIterator() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean hasNext() {
|
|
||||||
return next != header;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Node<K, V> nextNode() {
|
|
||||||
Node<K, V> e = next;
|
|
||||||
if (e == header) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
if (modCount != expectedModCount) {
|
|
||||||
throw new ConcurrentModificationException();
|
|
||||||
}
|
|
||||||
next = e.next;
|
|
||||||
return lastReturned = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void remove() {
|
|
||||||
if (lastReturned == null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
removeInternal(lastReturned, true);
|
|
||||||
lastReturned = null;
|
|
||||||
expectedModCount = modCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class EntrySet extends AbstractSet<Entry<K, V>> {
|
|
||||||
@Override public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Iterator<Entry<K, V>> iterator() {
|
|
||||||
return new LinkedTreeMapIterator<Entry<K, V>>() {
|
|
||||||
public Entry<K, V> next() {
|
|
||||||
return nextNode();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean contains(Object o) {
|
|
||||||
return o instanceof Entry && findByEntry((Entry<?, ?>) o) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean remove(Object o) {
|
|
||||||
if (!(o instanceof Entry)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node<K, V> node = findByEntry((Entry<?, ?>) o);
|
|
||||||
if (node == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
removeInternal(node, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void clear() {
|
|
||||||
LinkedTreeMap.this.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class KeySet extends AbstractSet<K> {
|
|
||||||
@Override public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Iterator<K> iterator() {
|
|
||||||
return new LinkedTreeMapIterator<K>() {
|
|
||||||
public K next() {
|
|
||||||
return nextNode().key;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean contains(Object o) {
|
|
||||||
return containsKey(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean remove(Object key) {
|
|
||||||
return removeInternalByKey(key) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void clear() {
|
|
||||||
LinkedTreeMap.this.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If somebody is unlucky enough to have to serialize one of these, serialize
|
|
||||||
* it as a LinkedHashMap so that they won't need Gson on the other side to
|
|
||||||
* deserialize it. Using serialization defeats our DoS defence, so most apps
|
|
||||||
* shouldn't use it.
|
|
||||||
*/
|
|
||||||
private Object writeReplace() throws ObjectStreamException {
|
|
||||||
return new LinkedHashMap<>(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
public interface ObjectConstructor<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new instance.
|
|
||||||
*/
|
|
||||||
public T construct();
|
|
||||||
}
|
|
@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2008 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
public final class Primitives {
|
|
||||||
private Primitives() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A map from primitive types to their corresponding wrapper types. */
|
|
||||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE;
|
|
||||||
|
|
||||||
/** A map from wrapper types to their corresponding primitive types. */
|
|
||||||
private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE;
|
|
||||||
|
|
||||||
// Sad that we can't use a BiMap. :(
|
|
||||||
|
|
||||||
static {
|
|
||||||
Map<Class<?>, Class<?>> primToWrap = new HashMap<>(16);
|
|
||||||
Map<Class<?>, Class<?>> wrapToPrim = new HashMap<>(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 true if this type is a primitive.
|
|
||||||
*/
|
|
||||||
public static boolean isPrimitive(Type type) {
|
|
||||||
return PRIMITIVE_TO_WRAPPER_TYPE.containsKey(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(Type type) {
|
|
||||||
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(
|
|
||||||
$Gson$Preconditions.checkNotNull(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) {
|
|
||||||
// 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(
|
|
||||||
$Gson$Preconditions.checkNotNull(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) {
|
|
||||||
// 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(
|
|
||||||
$Gson$Preconditions.checkNotNull(type));
|
|
||||||
return (unwrapped == null) ? type : unwrapped;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2010 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.*;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.TypeAdapters;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.MalformedJsonException;
|
|
||||||
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads and writes GSON parse trees over streams.
|
|
||||||
*/
|
|
||||||
public final class Streams {
|
|
||||||
private Streams() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a reader in any state and returns the next value as a JsonElement.
|
|
||||||
*/
|
|
||||||
public static JsonElement parse(JsonReader reader) throws JsonParseException {
|
|
||||||
boolean isEmpty = true;
|
|
||||||
try {
|
|
||||||
reader.peek();
|
|
||||||
isEmpty = false;
|
|
||||||
return TypeAdapters.JSON_ELEMENT.read(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.INSTANCE;
|
|
||||||
}
|
|
||||||
// The stream ended prematurely so it is likely a syntax error.
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
} catch (MalformedJsonException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new JsonIOException(e);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new JsonSyntaxException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the JSON element to the writer, recursively.
|
|
||||||
*/
|
|
||||||
public static void write(JsonElement element, JsonWriter writer) throws IOException {
|
|
||||||
TypeAdapters.JSON_ELEMENT.write(writer, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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 final class AppendableWriter extends Writer {
|
|
||||||
private final Appendable appendable;
|
|
||||||
private final CurrentWrite currentWrite = new CurrentWrite();
|
|
||||||
|
|
||||||
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,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal;
|
|
||||||
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectStreamClass;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do sneaky things to allocate objects without invoking their constructors.
|
|
||||||
*
|
|
||||||
* @author Joel Leitch
|
|
||||||
* @author Jesse Wilson
|
|
||||||
*/
|
|
||||||
public abstract class UnsafeAllocator {
|
|
||||||
public abstract <T> T newInstance(Class<T> c) throws Exception;
|
|
||||||
|
|
||||||
public static UnsafeAllocator create() {
|
|
||||||
// try JVM
|
|
||||||
// public class Unsafe {
|
|
||||||
// public Object allocateInstance(Class<?> type);
|
|
||||||
// }
|
|
||||||
try {
|
|
||||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
|
||||||
Field f = unsafeClass.getDeclaredField("theUnsafe");
|
|
||||||
f.setAccessible(true);
|
|
||||||
final Object unsafe = f.get(null);
|
|
||||||
final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
|
|
||||||
return new UnsafeAllocator() {
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T newInstance(Class<T> c) throws Exception {
|
|
||||||
assertInstantiable(c);
|
|
||||||
return (T) allocateInstance.invoke(unsafe, c);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// try dalvikvm, post-gingerbread
|
|
||||||
// public class ObjectStreamClass {
|
|
||||||
// private static native int getConstructorId(Class<?> c);
|
|
||||||
// private static native Object newInstance(Class<?> instantiationClass, int methodId);
|
|
||||||
// }
|
|
||||||
try {
|
|
||||||
Method getConstructorId = ObjectStreamClass.class
|
|
||||||
.getDeclaredMethod("getConstructorId", Class.class);
|
|
||||||
getConstructorId.setAccessible(true);
|
|
||||||
final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
|
|
||||||
final Method newInstance = ObjectStreamClass.class
|
|
||||||
.getDeclaredMethod("newInstance", Class.class, int.class);
|
|
||||||
newInstance.setAccessible(true);
|
|
||||||
return new UnsafeAllocator() {
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T newInstance(Class<T> c) throws Exception {
|
|
||||||
assertInstantiable(c);
|
|
||||||
return (T) newInstance.invoke(null, c, constructorId);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// try dalvikvm, pre-gingerbread
|
|
||||||
// public class ObjectInputStream {
|
|
||||||
// private static native Object newInstance(
|
|
||||||
// Class<?> instantiationClass, Class<?> constructorClass);
|
|
||||||
// }
|
|
||||||
try {
|
|
||||||
final Method newInstance = ObjectInputStream.class
|
|
||||||
.getDeclaredMethod("newInstance", Class.class, Class.class);
|
|
||||||
newInstance.setAccessible(true);
|
|
||||||
return new UnsafeAllocator() {
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> T newInstance(Class<T> c) throws Exception {
|
|
||||||
assertInstantiable(c);
|
|
||||||
return (T) newInstance.invoke(null, c, Object.class);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// give up
|
|
||||||
return new UnsafeAllocator() {
|
|
||||||
@Override
|
|
||||||
public <T> T newInstance(Class<T> c) {
|
|
||||||
throw new UnsupportedOperationException("Cannot allocate " + c);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the class can be instantiated by unsafe allocator. If the instance has interface or abstract modifiers
|
|
||||||
* throw an {@link java.lang.UnsupportedOperationException}
|
|
||||||
* @param c instance of the class to be checked
|
|
||||||
*/
|
|
||||||
private static void assertInstantiable(Class<?> c) {
|
|
||||||
int modifiers = c.getModifiers();
|
|
||||||
if (Modifier.isInterface(modifiers)) {
|
|
||||||
throw new UnsupportedOperationException("Interface can't be instantiated! Interface name: " + c.getName());
|
|
||||||
}
|
|
||||||
if (Modifier.isAbstract(modifiers)) {
|
|
||||||
throw new UnsupportedOperationException("Abstract class can't be instantiated! Class name: " + c.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal.bind;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Types;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
import java.lang.reflect.GenericArrayType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapt an array of objects.
|
|
||||||
*/
|
|
||||||
public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
|
|
||||||
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
|
||||||
Type type = typeToken.getType();
|
|
||||||
if (!(type instanceof GenericArrayType || type instanceof Class && ((Class<?>) type).isArray())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type componentType = $Gson$Types.getArrayComponentType(type);
|
|
||||||
TypeAdapter<?> componentTypeAdapter = gson.getAdapter(TypeToken.get(componentType));
|
|
||||||
return new ArrayTypeAdapter(
|
|
||||||
gson, componentTypeAdapter, $Gson$Types.getRawType(componentType));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Class<E> componentType;
|
|
||||||
private final TypeAdapter<E> componentTypeAdapter;
|
|
||||||
|
|
||||||
public ArrayTypeAdapter(Gson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) {
|
|
||||||
this.componentTypeAdapter =
|
|
||||||
new TypeAdapterRuntimeTypeWrapper<>(context, componentTypeAdapter, componentType);
|
|
||||||
this.componentType = componentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Object read(JsonReader in) throws IOException {
|
|
||||||
if (in.peek() == JsonToken.NULL) {
|
|
||||||
in.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<E> list = new ArrayList<>();
|
|
||||||
in.beginArray();
|
|
||||||
while (in.hasNext()) {
|
|
||||||
E instance = componentTypeAdapter.read(in);
|
|
||||||
list.add(instance);
|
|
||||||
}
|
|
||||||
in.endArray();
|
|
||||||
Object array = Array.newInstance(componentType, list.size());
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
Array.set(array, i, list.get(i));
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override public void write(JsonWriter out, Object array) throws IOException {
|
|
||||||
if (array == null) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.beginArray();
|
|
||||||
for (int i = 0, length = Array.getLength(array); i < length; i++) {
|
|
||||||
E value = (E) Array.get(array, i);
|
|
||||||
componentTypeAdapter.write(out, value);
|
|
||||||
}
|
|
||||||
out.endArray();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal.bind;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Types;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.ConstructorConstructor;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.ObjectConstructor;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapt a homogeneous collection of objects.
|
|
||||||
*/
|
|
||||||
public final class CollectionTypeAdapterFactory implements TypeAdapterFactory {
|
|
||||||
private final ConstructorConstructor constructorConstructor;
|
|
||||||
|
|
||||||
public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
|
||||||
this.constructorConstructor = constructorConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
|
||||||
Type type = typeToken.getType();
|
|
||||||
|
|
||||||
Class<? super T> rawType = typeToken.getRawType();
|
|
||||||
if (!Collection.class.isAssignableFrom(rawType)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
|
|
||||||
TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
|
|
||||||
ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);
|
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameter
|
|
||||||
TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
|
|
||||||
private final TypeAdapter<E> elementTypeAdapter;
|
|
||||||
private final ObjectConstructor<? extends Collection<E>> constructor;
|
|
||||||
|
|
||||||
public Adapter(Gson context, Type elementType,
|
|
||||||
TypeAdapter<E> elementTypeAdapter,
|
|
||||||
ObjectConstructor<? extends Collection<E>> constructor) {
|
|
||||||
this.elementTypeAdapter =
|
|
||||||
new TypeAdapterRuntimeTypeWrapper<>(context, elementTypeAdapter, elementType);
|
|
||||||
this.constructor = constructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Collection<E> read(JsonReader in) throws IOException {
|
|
||||||
if (in.peek() == JsonToken.NULL) {
|
|
||||||
in.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<E> collection = constructor.construct();
|
|
||||||
in.beginArray();
|
|
||||||
while (in.hasNext()) {
|
|
||||||
E instance = elementTypeAdapter.read(in);
|
|
||||||
collection.add(instance);
|
|
||||||
}
|
|
||||||
in.endArray();
|
|
||||||
return collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void write(JsonWriter out, Collection<E> collection) throws IOException {
|
|
||||||
if (collection == null) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.beginArray();
|
|
||||||
for (E element : collection) {
|
|
||||||
elementTypeAdapter.write(out, element);
|
|
||||||
}
|
|
||||||
out.endArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2011 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal.bind;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.JsonSyntaxException;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.bind.util.ISO8601Utils;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonReader;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonToken;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.ParsePosition;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter for Date. Although this class appears stateless, it is not.
|
|
||||||
* DateFormat captures its time zone and locale when it is created, which gives
|
|
||||||
* this class state. DateFormat isn't thread safe either, so this class has
|
|
||||||
* to synchronize its read and write methods.
|
|
||||||
*/
|
|
||||||
public final class DateTypeAdapter extends TypeAdapter<Date> {
|
|
||||||
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
|
|
||||||
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
|
|
||||||
@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
|
||||||
return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) new DateTypeAdapter() : null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final DateFormat enUsFormat
|
|
||||||
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US);
|
|
||||||
private final DateFormat localFormat
|
|
||||||
= DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
|
|
||||||
|
|
||||||
@Override public Date read(JsonReader in) throws IOException {
|
|
||||||
if (in.peek() == JsonToken.NULL) {
|
|
||||||
in.nextNull();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return deserializeToDate(in.nextString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized Date deserializeToDate(String json) {
|
|
||||||
try {
|
|
||||||
return localFormat.parse(json);
|
|
||||||
} catch (ParseException ignored) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return enUsFormat.parse(json);
|
|
||||||
} catch (ParseException ignored) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return ISO8601Utils.parse(json, new ParsePosition(0));
|
|
||||||
} catch (ParseException e) {
|
|
||||||
throw new JsonSyntaxException(json, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public synchronized void write(JsonWriter out, Date value) throws IOException {
|
|
||||||
if (value == null) {
|
|
||||||
out.nullValue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String dateFormatAsString = enUsFormat.format(value);
|
|
||||||
out.value(dateFormatAsString);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2014 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.massivecraft.massivecore.xlib.gson.internal.bind;
|
|
||||||
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.*;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.annotations.JsonAdapter;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.internal.ConstructorConstructor;
|
|
||||||
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a type T, looks for the annotation {@link JsonAdapter} and uses an instance of the
|
|
||||||
* specified class as the default type adapter.
|
|
||||||
*
|
|
||||||
* @since 2.3
|
|
||||||
*/
|
|
||||||
public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapterFactory {
|
|
||||||
private final ConstructorConstructor constructorConstructor;
|
|
||||||
|
|
||||||
public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
|
||||||
this.constructorConstructor = constructorConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) {
|
|
||||||
Class<? super T> rawType = targetType.getRawType();
|
|
||||||
JsonAdapter annotation = rawType.getAnnotation(JsonAdapter.class);
|
|
||||||
if (annotation == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals.
|
|
||||||
TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson,
|
|
||||||
TypeToken<?> type, JsonAdapter annotation) {
|
|
||||||
Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct();
|
|
||||||
|
|
||||||
TypeAdapter<?> typeAdapter;
|
|
||||||
if (instance instanceof TypeAdapter) {
|
|
||||||
typeAdapter = (TypeAdapter<?>) instance;
|
|
||||||
} else if (instance instanceof TypeAdapterFactory) {
|
|
||||||
typeAdapter = ((TypeAdapterFactory) instance).create(gson, type);
|
|
||||||
} else if (instance instanceof JsonSerializer || instance instanceof JsonDeserializer) {
|
|
||||||
JsonSerializer<?> serializer = instance instanceof JsonSerializer
|
|
||||||
? (JsonSerializer) instance
|
|
||||||
: null;
|
|
||||||
JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer
|
|
||||||
? (JsonDeserializer) instance
|
|
||||||
: null;
|
|
||||||
typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"@JsonAdapter value must be TypeAdapter, TypeAdapterFactory, "
|
|
||||||
+ "JsonSerializer or JsonDeserializer reference.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeAdapter != null && annotation.nullSafe()) {
|
|
||||||
typeAdapter = typeAdapter.nullSafe();
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeAdapter;
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user